下面是一段代码,这段代码连接两个文件以生成另一个文件。
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(),我的代码需要花费大量时间。我怎样才能加快上述循环?
答案 0 :(得分:4)
如果你没有 等待上一个文件在你开始下一个文件之前完成,你可以尝试这样的事情:
// 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);
答案 1 :(得分:0)
你可以产生一堆任务并执行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个订单带到厨房并回来接受第一个人的订单。
重点是,如果只是等待其中一个人带来额外服务员的结果而不一定会给你带来很大的性能提升。
显然,在这个类比中,服务员是一个线程,人们是需要完成的任务。在上面的解决方案中,你有一个服务员(线程池线程)服务所有人(创建所有进程),然后人员(进程)告诉他什么时候他们准备订购(即进程引发了事件)。然后他告诉厨房他们的订单(在工人上引发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);
});
}