2011-04-17 71 views
1

我需要從我的應用程序運行外部可執行文件的多個實例。這個可執行文件的平均運行時間約爲3分鐘。 我想重定向這些進程的輸出,並更新我的GUI中的進度條。 當然,我不想等他們回來,然後才能繼續使用我的應用程序。C#並行運行多個非阻塞外部程序

我想我應該爲每個實例創建一個線程,並在線程完成時更新我的​​進度條。

這是正確的做法嗎?

另外,你是否建議一個很好的資源/文檔來了解它是如何工作的?我只發現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

根據您的編輯,我在回覆中添加了更多評論 – 2011-04-17 17:19:13

+0

如果您使用.Net 4,則可以使用任務並行庫,而不用擔心自己管理進程:http://msdn.microsoft.com/EN-US /庫/ dd537609。aspx – joce 2011-05-15 14:06:35

回答

4

您應該使用ProcessProcessStartInfo。 您需要將ProcessStartInfo.UseShellExecute設置爲false,ErrorDialogfalse,RedirectStandardOutputtrue(也可能爲RedirectStandardError)。

你還需要提供一個代表對過程對象來處理通過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

你從很多浪費時間中拯救了我。 – 2014-11-14 14:25:25

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忙碌光標(不斷旋轉的圓圈)。

+0

嗨,維克多,的確看起來更好的方法。我編輯我的消息,因爲它不清楚。但在你的僞代碼表示中,如果我等待退出,進程將不會並行運行,所以我不會像@ Shyc2001建議的那樣使用WaitForExit。 – 2011-04-17 11:55:25

0

只需通過調用構造函數創建Process類的幾個實例,設置屬性以重定向輸出流,然後啓動它們。

只要您不調用WaitForExit方法,程序就不會等待被調用的進程退出。不需要多線程。

1

只是等待每個線程更新在沒有進度條結果發生......然後快速跳轉。3倍之前結束。你可以跳過進度條。

正確的方式做到這一點恕我直言,是計算在所有3個過程中所做的托爾工作:

TOTALWORK =時間1 +時間2 +時間3現在

,如果你有多個處理器,這將需要更像max(time1,time2,time3),但那沒關係。這是一個工作的代表。

有工作做了共享變量。每當一個進程做了更多的工作時,通過計算work-done + = my-work-increment來更新進度條。進展只是工作完成/總體工作。

這會得到好的結果,無論這些螺紋是否按順序或並行運行。既然你不知道事情將如何運行(你可能有一個處理器CPU),這是最好的方法。

0

如何創建TaskProgressInfo的一個ObservableCollection,
其中TaskProgressInfo是一個自定義類,對此你寫你的進步。

使用數據模板(目標類型= TaskProgressInfo)爲每個項目(任務)顯示一個進度條,將WPF listview綁定到該集合。

創建啓動外部應用程序,並監視它BackgroundWorkers的陣列。
每個後臺工作人員應更新其TaskProgressInfo,從而更新進度條的數據源。

完成後,每個BackgroundWorker應從ObservableCollection中刪除其TaskProgressInfo,從而從UI中刪除進度條。

由於BackgroundWorker使用後臺(UI)線程完成報表進度,因此對ObservableCollection的更改將通過其創建線程(線程安全)完成。

在幕後,.NET將使用ThreadPool - 一些backgroundworkers將共享線程。