C#并行运行多个非阻塞外部程序

我需要从我的应用程序运行多个外部可执行文件的实例。 此可执行文件的平均运行时间约为3分钟。 我想重定向这些进程的输出,并在我的GUI中更新进度条。 当然,在我继续使用我的应用程序之前,我不想等待他们返回。

我想我应该为每个实例创建一个线程,并在线程完成时更新我的​​进度条。

这是正确的方法吗?

另外,您是否建议使用良好的资源/文档来了解它的工作原理? 我发现只有http://www.dotnetperls.com/threadpool 。

编辑:这些进程是基于网络的,即:运行时间可能会有很大差异,具体取决于链路延迟/带宽。

关于进度条,我想在每次进程完成时更新它。 那有处理程序吗? 稍后我将根据流程输出添加更详细的更新,以增加每个执行步骤的进度。

编辑2:

感谢您的投入。 由于我可能需要运行大量进程(最多20个),并且我不想使带宽饱和,因此我将并行运行5个最大值。 每次进程结束时,我都会递增进度计数器(对于我的进度条),然后运行另一个进度计算器直到它们全部完成,使用:

Process p = new Process(); p.StartInfo.FileName = pathToApp; p.EnableRaisingEvents = true; p.Exited += OnCalibrationProcessExited; p.Start(); private void OnCalibrationProcessExited(object sender, EventArgs e) { runAnotherOne function } 

这是正确的还是有更优雅的方式来实现这一目标? 我不希望我的应用程序在执行过程中被阻止。 为此使用后台工作者会更好吗?

您应该使用ProcessProcessStartInfo 。 您需要将ProcessStartInfo.UseShellExecute设置为false ,将ErrorDialogfalseRedirectStandardOutputtrue (也可能设置为RedirectStandardError )。

您还需要为Process对象提供一个委托,以处理外部进程通过OutputDataReceived (以及可能还有ErrorDataReceived )生成的输出。

还有一个可以设置的Exited委托,只要进程退出就会调用它。

例:

 ProcessStartInfo processInfo = new ProcessStartInfo("Write500Lines.exe"); processInfo.ErrorDialog = false; processInfo.UseShellExecute = false; processInfo.RedirectStandardOutput = true; processInfo.RedirectStandardError = true; Process proc = Process.Start(processInfo); proc.ErrorDataReceived += (sender, errorLine) => { if (errorLine.Data != null) Trace.WriteLine(errorLine.Data); }; proc.OutputDataReceived += (sender, outputLine) => { if (outputLine.Data != null) Trace.WriteLine(outputLine.Data); }; proc.BeginErrorReadLine(); proc.BeginOutputReadLine(); proc.WaitForExit(); 

只是在更新进度条之前等待每个线程结束导致什么都没发生…然后快速跳转… 3次。 您也可以跳过进度条。

正确的方法恕我直言,将计算在所有3个过程中完成的代理工作:

totalwork = time1 + time2 + time3

现在,如果你有多个处理器,它将需要更多像max(time1,time2,time3),但没关系。 它是工作的代表。

完成工作的共享变量。 每次进程执行更多工作时,通过计算work-done + = my-work-increment来更新进度条。 进步只是工作完成/总工作。

无论线程是顺序运行还是并行运行,这都会产生良好的结果。 由于您不知道将如何运行(您可能只有一个处理器CPU),这是最好的方法。

只需通过调用构造函数创建Process类的多个实例,将属性设置为重定向输出流,然后启动它们。

只要不调用WaitForExit方法,您的程序就不会等待被调用进程退出。 不需要multithreading。

创建一个线程。

在那个线程(伪代码):

 Thread begins here for each externalApp Run the application with redirect output Wait for exit Update progress bar end for Thread ends here 

请参阅http://msdn.microsoft.com/en-us/library/ty0d8k56.aspx等待退出

或者……您想并行运行外部应用程序吗?

编辑:根据原始post中的最新更新:

如果您不知道实际进度,请不要使用常规进度条。 无限进度条或“工作”图标怎么样?

无限进度条可以是一个进度条,它可以填满并从开始直到完成所有操作。 工作图标就像Windows忙碌光标(永远旋转的圆圈)。

如何创建TaskProgressInfo的ObservableCollection,
其中TaskProgressInfo是一个自定义类,您可以在其中编写进度。

使用datatemplate(目标类型= TaskProgressInfo)将WPF列表视图绑定到该集合,以显示每个项目(任务)的进度条。

创建一个BackgroundWorkers数组,用于启动外部应用程序并对其进行监控。
每个后台工作者都应更新其TaskProgressInfo,从而更新进度条的数据源。

完成后,每个BackgroundWorker都应从ObservableCollection中删除其TaskProgressInfo,从而从UI中删除进度条。

由于BackgroundWorker使用后台(UI)线程进行报告进度和完成,因此对ObservableCollection的更改将由其创建线程(线程安全)完成。

在幕后,.NET将使用ThreadPool – 一些后台工作者将共享线程。