Есть ли асинхронный эквивалент процесса.Начать?
Как следует из названия, есть ли эквивалент Process.Start
(позволяет запустить другое приложение или пакетный файл), что я мог ожидать?
Я играю с небольшим консольным приложением, и это казалось идеальным местом для использования async и await, но я не могу найти никакой документации для этого сценария.
то, что я думаю, что-то вроде этих строк:
void async RunCommand()
{
var result = await Process.RunAsync("command to run");
}
3 ответа:
Process.Start()
только запускает процесс, он не ждет, пока он закончится, так что это не имеет большого смысла, чтобы сделать этоasync
. Если вы все еще хотите сделать это, вы можете сделать что-то вродеawait Task.Run(() => Process.Start(fileName))
.но, если вы хотите асинхронно ждать завершения процесса, вы можете использовать the
Exited
событие вместе сTaskCompletionSource
:static Task<int> RunProcessAsync(string fileName) { var tcs = new TaskCompletionSource<int>(); var process = new Process { StartInfo = { FileName = fileName }, EnableRaisingEvents = true }; process.Exited += (sender, args) => { tcs.SetResult(process.ExitCode); process.Dispose(); }; process.Start(); return tcs.Task; }
вот мое мнение, основанное на svick по. Он добавляет перенаправление вывода, сохранение кода выхода и немного лучшую обработку ошибок (удаление
Process
объект, даже если он не может быть запущен):public static async Task<int> RunProcessAsync(string fileName, string args) { using (var process = new Process { StartInfo = { FileName = fileName, Arguments = args, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true }, EnableRaisingEvents = true }) { return await RunProcessAsync(process).ConfigureAwait(false); } } private static Task<int> RunProcessAsync(Process process) { var tcs = new TaskCompletionSource<int>(); process.Exited += (s, ea) => tcs.SetResult(process.ExitCode); process.OutputDataReceived += (s, ea) => Console.WriteLine(ea.Data); process.ErrorDataReceived += (s, ea) => Console.WriteLine("ERR: " + ea.Data); bool started = process.Start(); if (!started) { //you may allow for the process to be re-used (started = false) //but I'm not sure about the guarantees of the Exited event in such a case throw new InvalidOperationException("Could not start process: " + process); } process.BeginOutputReadLine(); process.BeginErrorReadLine(); return tcs.Task; }
вот еще один подход. Аналогичная концепция svick и Охад это ответы, но с помощью метода расширения на
Process
тип.метод расширения:
public static Task RunAsync(this Process process) { var tcs = new TaskCompletionSource<object>(); process.EnableRaisingEvents = true; process.Exited += (s, e) => tcs.TrySetResult(null); // not sure on best way to handle false being returned if (!process.Start()) tcs.SetException(new Exception("Failed to start process.")); return tcs.Task; }
пример использования в методе, содержащем:
public async Task ExecuteAsync(string executablePath) { using (var process = new Process()) { // configure process process.StartInfo.FileName = executablePath; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; // run process asynchronously await process.RunAsync(); // do stuff with results Console.WriteLine($"Process finished running at {process.ExitTime} with exit code {process.ExitCode}"); };// dispose process }