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 }
这是正确的还是有更优雅的方式来实现这一目标? 我不希望我的应用程序在执行过程中被阻止。 为此使用后台工作者会更好吗?
您应该使用Process
和ProcessStartInfo
。 您需要将ProcessStartInfo.UseShellExecute
设置为false
,将ErrorDialog
为false
, RedirectStandardOutput
为true
(也可能设置为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 – 一些后台工作者将共享线程。