首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有超时的WaitForExitAsync

带有超时的WaitForExitAsync
EN

Stack Overflow用户
提问于 2022-01-07 13:34:30
回答 3查看 891关注 0票数 5

因此,我注意到有一个名为WaitForExit的方法,它接受作为参数的int (毫秒),因此如果进程无法退出自身,那么几秒钟后我就会将其关闭。

就像这样。

代码语言:javascript
运行
复制
if (!CMD.WaitForExit(3000))
    CMD.Kill();

问题是,同时我想保存输出,所以我注意到有一个异步方法WaitForExitAsync,但这个方法不接受这些毫秒。

代码语言:javascript
运行
复制
// Wait for exit async...
// Meanwhile save the output till it kills itself.

while (CMD.StandardOutput.ReadLine() != null) 
    standard_output = StandardOutput.ReadLine();

知道怎么做吗?谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-01-07 13:40:11

您需要使用CancellationTokenSource。它有一个克托尔,它接受一个TimeSpan

代码语言:javascript
运行
复制
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try 
{
   await CMD.WaitForExitAsync(timeoutSignal.Token);
} catch (OperationCanceledException)
{
   CMD.Kill();
}

当CTS发出信号时,等待的操作将抛出一个OperationCanceledException。因此,您需要将await调用包装到try-catch中,以便正确处理已取消的操作。

更新#1:用异步等待退出捕获STDOUT

朴素方法

首先,让我与您分享代码的天真版本。

代码语言:javascript
运行
复制
Console.WriteLine("Launch ping with fifteen retries");
var terminal = Process.Start(new ProcessStartInfo("/sbin/ping")
{
    RedirectStandardOutput = true,
    Arguments = "-c 15 stackoverflow.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命令
  • 我将堆栈溢出执行了15次,以确保命令运行超过3秒。
  • 我已经将StandardOutput读取移动到一个单独的线程(Task.Run)
    • 否则,取消信号将不会产生任何影响。

  • 其余代码与上面+调试日志相同

建议的方法

Process类确实公开了从StandardOutput异步读取数据的功能,而无需执行额外的技巧。

代码语言:javascript
运行
复制
Console.WriteLine("Launch ping with fifteen retries");
var terminal = new Process()
{
    StartInfo = new ProcessStartInfo("/sbin/ping")
    {
        RedirectStandardOutput = true,
        Arguments = "-c 15 stackoverflow.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方法来告诉进程,每当标准输出上有新数据可用时,就会触发上面的事件处理程序。
票数 6
EN

Stack Overflow用户

发布于 2022-06-01 11:10:57

新的.NET 6附带了允许异步等待超时任务的WaitAsync方法。

代码语言:javascript
运行
复制
await process.WaitForExitAsync().WaitAsync(TimeSpan.FromMilliseconds(1000));

if (!process.HasExited)
{
    //timeout!
}
票数 1
EN

Stack Overflow用户

发布于 2022-05-25 19:37:41

它有一个争论需要毫秒

代码语言:javascript
运行
复制
WaitForExitAsync(process, timeout);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70622033

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档