[英]c# Using Process.start () efficiently
下面是一段代碼,這段代碼將兩個文件連接起來生成另一個文件。
foreach (string jpegfile in files)
{
string fileName = jpegfile + ".dcm";
string ConfigFile =GetFileNameWithoutExtension(jpegfile) + ".cfg";
string destFile = System.IO.Path.Combine(DirectoryPath, fileName);
string command = "/C " + batFileName + " -C " + patientConfigFile + " " + jpegfile + " " + destFile;
try
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = command;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit();
this.counter++;
// Report progress as a percentage of the total task.
int percentComplete =
(int)((float)this.counter / (float)form.sumofImages * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached = percentComplete;
worker.ReportProgress(percentComplete);
}
}
catch (Exception exp)
{
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result;
result = MessageBox.Show("Batch File execution error " + exp, "Warning", buttons);
}
}
我的問題是,如果我在 start() 之后使用 waitforexit() 我的代碼需要很長時間。 我怎樣才能加快上述循環?
如果您不必等待前一個文件到結束你開始下一個之前,你可以嘗試這樣的事:
// for each file, spawn a task to do your processing
var tasks = (from jpegfile in files
select Task.Run(() =>
{
// set up your process here...
process.Start();
// task won't be done until process exits
process.WaitForExit();
}).ToArray();
// Wait for all the tasks to be done
Task.WaitAll(tasks);
您可以生成一堆任務並執行 Task.WaitAll,如 Matt Burland 的回答所示。
其他一些選項如下。 (我還沒有對這些進行過徹底的測試,所以你可能想要這樣做)。 首先,您可以使用事件代替 WaitForExit:
private int counter = 0;
int sumOfImages = 10; // Set this to the number of files
private void ProcessStart(List<string> files)
{
foreach (string file in files)
{
Process process = new Process();
process.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "someCommand";
process.StartInfo.CreateNoWindow = true;
process.EnableRaisingEvents = true;
process.Exited += Process_Exited;
process.Start();
}
}
private void Process_Exited(object sender, EventArgs e)
{
int result = Interlocked.Increment(ref counter);
int percentComplete = ((result / sumOfImages) * 100);
worker.ReportProgress(percentComplete);
}
如果您願意,您可以將整個內容放在線程池中。 我實際上喜歡將其作為答案 - 受 CPU 限制的部分是創建和啟動進程,這會將其放在后台線程上,因此它不會掛起您的 UI。 它將消除等待結果的開銷,這不受 CPU 限制。
這是一個插圖。 假設你去一家有 10 個人的餐廳。 當服務員來的時候,10個人中有9個人已經准備好點菜了。 服務員碰巧先問那個人點菜。 這時候,一桌人要么等着他做決定,要么服務生接受其他9人點的菜,然后回到第一個人。 很可能在原來的服務員接受其他 9 個訂單時,引入一個額外的服務員來等待第一個人的訂單是毫無意義的。 如果絕對必要,服務員可以將 9 個訂單帶到廚房,然后再回來接受第一個人的訂單。
重點是,如果只是等待其中一個帶來額外服務員的人的結果,並不一定會給您帶來很大的性能提升。
顯然,在這個比喻中,服務員是一個線程,而人是需要完成的任務。 在上面的解決方案中,你有一個服務員(線程池線程)為所有的人服務(創建所有的進程),然后這些人(進程)告訴他他們什么時候准備好點菜(即進程提出事件)。 然后他告訴廚房他們的訂單(在 Worker 上引發 ReportProgress 事件)。
另一種選擇是 Parallel.ForEach 循環:
private void ProcessStart(List<string> files)
{
int sumOfImages = files.Count;
int count = 0;
string command = "";
Parallel.ForEach(files,
delegate (string file)
{
Process process = new Process();
process.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = command;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit();
int result = Interlocked.Increment(ref count);
int percentComplete = ((result / sumOfImages) * 100);
worker.ReportProgress(percentComplete);
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.