Task.Delay在一两天后停止连续循环程序

问题描述 投票:-3回答:1

我有一个.NET Web API,我继续在循环中继续运行Task方法(直到应用程序运行)。

我在调用下一个LoopMethod任务之前使用的是await Task.Delay(120000)。 API连续运行1或2天,然后停在上一个日志文件声明所示的位置,log.Debug("Before Task Delay..");

这意味着在某些时候任务await Task.Delay(120000);永远不会完成。

有什么我想念的吗?

这是我正在使用的示例代码段格式

我正在使用递归,因为下一个LoopMethod参数取决于前一个LoopMethod的返回值。

public async Task<HttpStatusCode> LoopMethod(string token) 
{
    var responseHttpStatusCode = HttpStatusCode.Unused;

   string NextToken =  await DoSomething();

    log.Debug("Before Task Delay..");
    await Task.Delay(120000);
    log.Debug("After Task Delay..");

    await LoopMethod(NextToken); 

    return responseHttpStatusCode;
}
c# asp.net-web-api async-await task
1个回答
4
投票

我不确定这是从您的网络服务器或您的客户端代码调用的。如果它是网络服务器,你不应该像这样运行渴望运行的任务。 ApplicationPool将最终回收并拆除它。

然而,我的蜘蛛般的感觉告诉我这是客户端,你刚刚用完堆栈,这反过来导致StackOverflowException

堆栈溢出的最常见原因是过度深度或无限递归,其中函数调用自身的次数太多,以至于存储与每个调用关联的变量和信息所需的空间超出了堆栈的范围。

如果你真的需要这样做,只考虑一个while循环

public async Task<HttpStatusCode> LoopMethod() 
{

    while(true)
    {
       ...

       await Task.Delay(120000);

       if(condition)
          //break or return

       ...
      }
}

或者正如John Wu所说,只需使用具有状态的计时器

如果这是一个网络服务器,请考虑使用服务进行轮询,该服务旨在坚持而不是回收

从评论更新

From Kevin Gosse

虽然我同意在这里使用递归没有意义,但请注意,这里没有实际的递归。由于async / await以及Task.Delay永远不会同步完成的事实,每个continuation都有自己的调用堆栈,堆栈使用量实际上并没有增长。您可以通过在方法开头记录Environment.StackTrace的值来说服自己。也就是说,你仍然在每次迭代时创建任务,所以你在某些时候会耗尽内存

© www.soinside.com 2019 - 2024. All rights reserved.