我需要从我的应用程序运行多个外部可执行文件的实例。此可执行文件的平均运行时间约为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
}
这是正确的还是有更优雅的方式来实现这一目标? 我不希望在执行过程中阻止我的应用程序。 为此使用后台工作者会更好吗?
答案 0 :(得分:4)
您应该使用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();
答案 1 :(得分:1)
在更新进度条之前等待每个线程结束都不会发生任何事情...然后快速跳转... 3次。您也可以跳过进度条。
正确的方法恕我直言,将计算在所有3个过程中完成的代理工作:
totalwork = time1 + time2 + time3
现在,如果你有多个处理器,它将需要更多像max(time1,time2,time3),但没关系。它是工作的代表。
为工作完成提供共享变量。每次进程执行更多工作时,通过计算work-done + = my-work-increment来更新进度条。进步只是工作完成/总工作。
无论线程是顺序运行还是并行运行,这都会产生良好的结果。由于您不知道将如何运行(您可能只有一个处理器CPU),这是最好的方法。
答案 2 :(得分:0)
创建一个单独的线程。
在该线程中(伪代码):
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等待退出
或者......你想并行运行外部应用程序吗?
编辑:根据原始帖子中的最新更新:
如果您不知道实际进度,请不要使用常规进度条。无限进度条或“工作”图标怎么样?
无限进度条可以是一个进度条,它会填满并从开始直到完成所有操作。工作图标就像Windows忙碌光标(永远旋转的圆圈)。
答案 3 :(得分:0)
只需通过调用构造函数创建Process类的多个实例,将属性设置为重定向输出流,然后启动它们。
只要您不调用WaitForExit方法,您的程序就不会等待被调用进程退出。不需要多线程。
答案 4 :(得分:0)
如何创建TaskProgressInfo的ObservableCollection,
其中TaskProgressInfo是一个自定义类,您可以在其中编写进度。
使用datatemplate(目标类型= TaskProgressInfo)将WPF列表视图绑定到该集合,以显示每个项目(任务)的进度条。
创建一个BackgroundWorkers数组,用于启动外部应用程序并对其进行监控
每个后台工作者都应该更新其TaskProgressInfo,从而更新进度条的数据源。
完成后,每个BackgroundWorker都应从ObservableCollection中删除其TaskProgressInfo,从而从UI中删除进度条。
由于BackgroundWorker使用后台(UI)线程进行报告进度和完成, 对ObservableCollection的更改将由其创建线程(线程安全)完成。
在幕后,.NET将使用ThreadPool - 一些后台工作人员将共享线程。