WaitForExitAsync 超时
WaitForExitAsync with a timeout
所以我注意到有一个名为 WaitForExit
的方法接受 int 作为参数(毫秒),所以如果进程无法自行退出,我会在几秒钟后将其杀死。
像这样。
if (!CMD.WaitForExit(3000))
CMD.Kill();
事情是同时我想保存输出,所以我注意到有一个异步方法WaitForExitAsync
但是这个方法不接受这些毫秒。
// Wait for exit async...
// Meanwhile save the output till it kills itself.
while (CMD.StandardOutput.ReadLine() != null)
standard_output = StandardOutput.ReadLine();
知道怎么做吗?谢谢!
您需要使用 CancellationTokenSource
。它有一个 ctor 接受 TimeSpan
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await CMD.WaitForExitAsync(timeoutSignal.Token);
} catch (OperationCanceledException)
{
CMD.Kill();
}
当 CTS 发出信号时,等待的操作将抛出 OperationCanceledException
。因此,您需要将 await
调用包装到 try
-catch
中以正确处理取消的操作。
更新 #1:通过异步等待退出捕获 STDOUT
天真的方法
首先让我与您分享代码的原始版本
Console.WriteLine("Launch ping with fifteen retries");
var terminal = Process.Start(new ProcessStartInfo("/sbin/ping")
{
RedirectStandardOutput = true,
Arguments = "-c 15 whosebug.com",
UseShellExecute = false,
});
_ = Task.Run(() =>
{
string line = null;
while ((line = terminal.StandardOutput.ReadLine()) != null)
Console.WriteLine(line);
});
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await terminal.WaitForExitAsync(timeoutSignal.Token);
Console.WriteLine("Ping has been Finished");
}
catch (OperationCanceledException)
{
terminal.Kill();
Console.WriteLine("Ping has been Terminated");
}
- 我在 Macintosh 机器上使用 .NET,所以我没有
ping.exe
而不是 运行 /sbin/ping
命令
- 我 ping Whosebug 十五次以确保命令 运行s 超过 3 秒
- 我已将
StandardOutput
阅读移至单独的线程 (Task.Run
)
- 否则,取消信号不会有任何效果
- 其余代码同上+调试日志
建议的方法
Process
class 确实提供了从 StandardOutput
异步读取数据的能力,而无需执行额外的技巧
Console.WriteLine("Launch ping with fifteen retries");
var terminal = new Process()
{
StartInfo = new ProcessStartInfo("/sbin/ping")
{
RedirectStandardOutput = true,
Arguments = "-c 15 whosebug.com",
UseShellExecute = false,
}
};
terminal.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
terminal.Start();
terminal.BeginOutputReadLine();
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await terminal.WaitForExitAsync(timeoutSignal.Token);
Console.WriteLine("Ping has been Finished");
}
catch (OperationCanceledException)
{
terminal.Kill();
Console.WriteLine("Ping has been Terminated");
}
让我只强调不同之处
- 不是立即启动进程,而是首先创建一个进程并指定其
StartInfo
属性
- 然后我们订阅
OutputDataReceived
事件
- 它的 EventArgs'
Data
属性 包含新的可用信息
- 订阅后我们可以调用
Start
方法
- 最后我们需要调用
BeginOutputReadLine
方法来告诉 Process 在标准输出上有新数据可用时触发上述事件处理程序
它有一个参数需要毫秒
WaitForExitAsync(process, timeout);
新的 .NET 6 附带 WaitAsync
方法,允许异步等待任务 超时 。
await process.WaitForExitAsync().WaitAsync(TimeSpan.FromMilliseconds(1000));
if (!process.HasExited)
{
//timeout!
}
所以我注意到有一个名为 WaitForExit
的方法接受 int 作为参数(毫秒),所以如果进程无法自行退出,我会在几秒钟后将其杀死。
像这样。
if (!CMD.WaitForExit(3000))
CMD.Kill();
事情是同时我想保存输出,所以我注意到有一个异步方法WaitForExitAsync
但是这个方法不接受这些毫秒。
// Wait for exit async...
// Meanwhile save the output till it kills itself.
while (CMD.StandardOutput.ReadLine() != null)
standard_output = StandardOutput.ReadLine();
知道怎么做吗?谢谢!
您需要使用 CancellationTokenSource
。它有一个 ctor 接受 TimeSpan
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await CMD.WaitForExitAsync(timeoutSignal.Token);
} catch (OperationCanceledException)
{
CMD.Kill();
}
当 CTS 发出信号时,等待的操作将抛出 OperationCanceledException
。因此,您需要将 await
调用包装到 try
-catch
中以正确处理取消的操作。
更新 #1:通过异步等待退出捕获 STDOUT
天真的方法
首先让我与您分享代码的原始版本
Console.WriteLine("Launch ping with fifteen retries");
var terminal = Process.Start(new ProcessStartInfo("/sbin/ping")
{
RedirectStandardOutput = true,
Arguments = "-c 15 whosebug.com",
UseShellExecute = false,
});
_ = Task.Run(() =>
{
string line = null;
while ((line = terminal.StandardOutput.ReadLine()) != null)
Console.WriteLine(line);
});
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await terminal.WaitForExitAsync(timeoutSignal.Token);
Console.WriteLine("Ping has been Finished");
}
catch (OperationCanceledException)
{
terminal.Kill();
Console.WriteLine("Ping has been Terminated");
}
- 我在 Macintosh 机器上使用 .NET,所以我没有
ping.exe
而不是 运行/sbin/ping
命令 - 我 ping Whosebug 十五次以确保命令 运行s 超过 3 秒
- 我已将
StandardOutput
阅读移至单独的线程 (Task.Run
)- 否则,取消信号不会有任何效果
- 其余代码同上+调试日志
建议的方法
Process
class 确实提供了从 StandardOutput
异步读取数据的能力,而无需执行额外的技巧
Console.WriteLine("Launch ping with fifteen retries");
var terminal = new Process()
{
StartInfo = new ProcessStartInfo("/sbin/ping")
{
RedirectStandardOutput = true,
Arguments = "-c 15 whosebug.com",
UseShellExecute = false,
}
};
terminal.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
terminal.Start();
terminal.BeginOutputReadLine();
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await terminal.WaitForExitAsync(timeoutSignal.Token);
Console.WriteLine("Ping has been Finished");
}
catch (OperationCanceledException)
{
terminal.Kill();
Console.WriteLine("Ping has been Terminated");
}
让我只强调不同之处
- 不是立即启动进程,而是首先创建一个进程并指定其
StartInfo
属性 - 然后我们订阅
OutputDataReceived
事件- 它的 EventArgs'
Data
属性 包含新的可用信息
- 它的 EventArgs'
- 订阅后我们可以调用
Start
方法 - 最后我们需要调用
BeginOutputReadLine
方法来告诉 Process 在标准输出上有新数据可用时触发上述事件处理程序
它有一个参数需要毫秒
WaitForExitAsync(process, timeout);
新的 .NET 6 附带 WaitAsync
方法,允许异步等待任务 超时 。
await process.WaitForExitAsync().WaitAsync(TimeSpan.FromMilliseconds(1000));
if (!process.HasExited)
{
//timeout!
}