多任务环境中的流程执行



我正在尝试在我的程序中执行一些命令,为此我正在使用System.Diagnostics.Process.我设法让它工作,当我 1 个执行命令时,返回是正确的。然后,我尝试通过为每个流程执行创建任务来加快流程,这就是我遇到问题的地方。

以下是执行命令的类:

class ProcessExec
{
public string Start(string command)
{
string res = "";
Process process = new Process();
process.EnableRaisingEvents = true;
process.StartInfo.FileName = "powershell.exe";
process.StartInfo.Arguments = command;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
{
res = res + e.Data;
};
process.Start();
process.BeginOutputReadLine();
process.WaitForExit(10000);
return res;
}
}

这是我的主要:

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start");
List<Task> tasks = new List<Task>();
ProcessExec exec = new ProcessExec();
Stopwatch sw = new Stopwatch();
sw.Start();
string res1 = "";
tasks.Add(Task.Run(() => { res1 = exec.Start("date"); }));
string res2 = "";
tasks.Add(Task.Run(() => { res2 = exec.Start("hostname"); }));
string res3 = "";
tasks.Add(Task.Run(() => { res3 = exec.Start("date"); }));
string res4 = "";
tasks.Add(Task.Run(() => { res4 = exec.Start("date"); }));
string res5 = "";
tasks.Add(Task.Run(() => { res5 = exec.Start("date"); }));
string res6 = "";
tasks.Add(Task.Run(() => { res6 = exec.Start("ipconfig"); }));
string res7 = "";
tasks.Add(Task.Run(() => { res7 = exec.Start("date"); }));
string res8 = "";
tasks.Add(Task.Run(() => { res8 = exec.Start("date"); }));
Task.WaitAll(tasks.ToArray());
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalSeconds);
Console.WriteLine("1 - " + res1);
Console.WriteLine("2 - " + res2);
Console.WriteLine("3 - " + res3);
Console.WriteLine("4 - " + res4);
Console.WriteLine("5 - " + res5);
Console.WriteLine("6 - " + res6);
Console.WriteLine("7 - " + res7);
Console.WriteLine("8 - " + res8);
Console.WriteLine("End");
Console.ReadKey();
}
}

这是我的输出:

Start
7,4867498
1 - 22 de julho de 2017 10:25:46    
2 -    
3 - 22 de julho de 2017 10:25:48
4 - 22 de julho de 2017 10:25:48    
5 -    
6 -    
7 - 22 de julho de 2017 10:25:48
8 - 22 de julho de 2017 10:25:48
End

现在,我认为我的问题与 OutputDataReceived 事件处于不同的线程中有关,但我不完全确定。任何人都知道问题是什么,我该如何解决?

如果你不仅可以解释你得到什么输出,而且能解释你期望什么输出,那就更好了。也就是说,您问的是为什么某些(但不是全部(命令具有空输出。是的,这是因为这些命令显然花费的时间比您分配的 10 秒长,因此您的方法在读取输出之前返回。

事实是,如果您希望您的方法在该过程完成之前不返回,则根本没有理由使用WaitForExit()。我知道这听起来有悖常理,但您必须在此处使用WaitForExit()的原因是您选择异步使用进程输出。但是没有理由这样做,因为您希望流程的处理是同步的。

所以,就这样做吧。您可以调用Process.StandardOutput.ReadToEnd(),这将阻塞直到进程退出,然后返回所有输出。此外,您的类似乎没有任何理由是非静态的,因为它在方法中除了本地状态之外没有任何状态。

所以这样的东西会更好:

static class ProcessExec
{
public static string Start(string command)
{
Process process = new Process();
process.StartInfo.FileName = "powershell.exe";
process.StartInfo.Arguments = command;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
return process.StandardOutput.ReadToEnd();
}
}

关于您的实现,我要更改的另一件事是局部变量的使用。鉴于您使用Task,最好在Task对象本身中表示命令的结果,而不是为您执行的每个命令捕获局部变量。

例如:

static void Main(string[] args)
{
Console.WriteLine("Start");
List<Task<string>> tasks = new List<Task<string>>();
Stopwatch sw = new Stopwatch();
sw.Start();
tasks.Add(Task.Run(() => ProcessExec.Start("date")));
tasks.Add(Task.Run(() => ProcessExec.Start("hostname")));
tasks.Add(Task.Run(() => ProcessExec.Start("date")));
tasks.Add(Task.Run(() => ProcessExec.Start("date")));
tasks.Add(Task.Run(() => ProcessExec.Start("date")));
tasks.Add(Task.Run(() => ProcessExec.Start("ipconfig")));
tasks.Add(Task.Run(() => ProcessExec.Start("date")));
tasks.Add(Task.Run(() => ProcessExec.Start("date")));
Task.WaitAll(tasks);
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalSeconds);
Console.WriteLine(string.Join(Environment.NewLine,
tasks.Select((t, i) => $"{i + 1} - {t.Result}")));
Console.WriteLine("End");
Console.ReadKey();
}

然后,您不需要变量,并且使用循环变量可以轻松检索命令结果,而不必单独命名每个变量。

最新更新