如何使用C#多线程执行控制台应用程序?
用C#多线程并行执行外部应用程序
嘿,看起来你已经写好了单线程重复执行外部程序的代码,但其实当前的实现还是串行执行的——因为在单个线程里每次启动进程后都调用了WaitForExit(),得等上一个进程跑完才会启动下一个。如果想真正利用多线程的并行优势,让多个外部程序同时跑,咱可以这么改:
首先先看看你现有的单线程代码:
public static void OneThread() { DateTime startTime = DateTime.Now; Thread t11 = new Thread(() => { for (int i = 0; i <= 5; i++) { var proc = new Process(); proc.StartInfo.FileName = @"C:\Users\consoleapp.exe"; proc.StartInfo.Arguments = "-v -s -a"; proc.Start(); proc.WaitForExit(); var exitCode = proc.ExitCode; proc.Close(); } }); t11.Start(); t11.Join(); Console.WriteLine("execution 1 thread 5 times in {0} seconds", (DateTime.Now - startTime).TotalSeconds); }
方案1:用Thread类实现并行执行
我们可以创建多个线程,每个线程负责启动一次外部程序,然后等待所有线程完成。这样多个进程就能同时运行了:
public static void MultiThreadWithThreadClass() { DateTime startTime = DateTime.Now; const int runTimes = 5; var threads = new List<Thread>(); for (int i = 0; i < runTimes; i++) { // 注意:循环变量要捕获当前值,否则可能出现线程共享变量的问题 int iteration = i; var thread = new Thread(() => { // 用using自动释放Process资源,比手动Close更可靠 using (var proc = new Process()) { proc.StartInfo.FileName = @"C:\Users\consoleapp.exe"; proc.StartInfo.Arguments = "-v -s -a"; proc.Start(); proc.WaitForExit(); var exitCode = proc.ExitCode; // 加个锁保证控制台输出不乱序(可选) lock (Console.Out) { Console.WriteLine($"Iteration {iteration} completed with exit code: {exitCode}"); } } }); threads.Add(thread); thread.Start(); } // 等待所有线程执行完成 foreach (var thread in threads) { thread.Join(); } Console.WriteLine($"Multi-thread (Thread class) execution {runTimes} times in { (DateTime.Now - startTime).TotalSeconds } seconds"); }
方案2:用Task(推荐,更现代的异步方式)
在.NET里,Task是更推荐的异步/多线程编程模型,代码更简洁,还能利用Task的各种便捷API:
public static async Task MultiThreadWithTaskAsync() { DateTime startTime = DateTime.Now; const int runTimes = 5; var tasks = new List<Task>(); for (int i = 0; i < runTimes; i++) { int iteration = i; var task = Task.Run(() => { using (var proc = new Process()) { proc.StartInfo.FileName = @"C:\Users\consoleapp.exe"; proc.StartInfo.Arguments = "-v -s -a"; proc.Start(); proc.WaitForExit(); var exitCode = proc.ExitCode; lock (Console.Out) { Console.WriteLine($"Iteration {iteration} completed with exit code: {exitCode}"); } } }); tasks.Add(task); } // 异步等待所有任务完成 await Task.WhenAll(tasks); Console.WriteLine($"Multi-thread (Task) execution {runTimes} times in { (DateTime.Now - startTime).TotalSeconds } seconds"); }
额外注意事项
- 资源释放:一定要用
using包裹Process实例,因为它实现了IDisposable,using会自动帮你释放相关资源,避免内存泄漏。 - 并发控制:如果外部程序不能同时运行太多实例(比如依赖同一个文件、端口),可以用
SemaphoreSlim来限制并发数:// 限制最多同时运行3个进程 var semaphore = new SemaphoreSlim(3); // 在每个任务里先等待信号量 await semaphore.WaitAsync(); try { // 执行进程代码 } finally { semaphore.Release(); } - 错误处理:建议给进程启动和执行的代码加上
try-catch,避免单个进程的异常导致整个多线程逻辑崩溃。 - 线程安全:像
Console.WriteLine这种共享资源的操作,最好加锁或者用线程安全的方式输出,否则会出现乱码或者重叠输出的情况。
内容的提问来源于stack exchange,提问作者Neo
相关产品推荐
相关产品推荐

