c# - await Task.Delay 花费的时间比预期的要长

标签 c# .net asynchronous task-parallel-library async-await

我编写了一个多线程应用程序,它广泛使用了异步/等待。它应该在预定的时间下载一些东西。为此,它使用“await Task.Delay”。有时它每分钟发送数千个请求。

它按预期工作,但有时我的程序需要记录一些大的东西。当它这样做时,它会序列化许多对象并将它们保存到一个文件中。在那段时间里,我注意到我的计划任务执行得太晚了。我已将所有日志记录放到优先级最低的单独线程中,问题不再经常发生,但它仍然会发生。事情是,我想知道它什么时候发生,以便知道我必须使用类似的东西:

var delayTestDate = DateTime.Now;
await Task.Delay(5000);
if((DateTime.Now - delayTestDate).TotalMilliseconds > 6000/*delays up to 1 second are tolerated*/) Console.WriteLine("The task has been delayed!");

此外,我发现我也使用的“Task.Run”也会导致延迟。为了监控它,我不得不使用更难看的代码:

var delayTestDate = DateTime.Now;
await Task.Run(() =>
{
  if((DateTime.Now - delayTestDate).TotalMilliseconds > 1000/*delays up to 1 second are tolerated*/) Console.WriteLine("The task has been delayed!");
  //do some stuff
  delayTestDate = DateTime.Now;
});
if((DateTime.Now - delayTestDate).TotalMilliseconds > 1000/*delays up to 1 second are tolerated*/) Console.WriteLine("The task has been delayed!");

我必须在每个 await 和 Task.Run 之前和之后以及在每个异步函数中使用它,这既丑陋又不方便。我不能将它放入一个单独的函数中,因为它必须是异步的,而且无论如何我都必须等待它。有人知道更优雅的解决方案吗?

编辑:

我在评论中提供的一些信息:

正如@YuvalItzchakov 所注意到的,问题可能是由线程池饥饿引起的。这就是为什么我使用 System.Threading.Thread 来处理线程池之外的日志记录,但正如我所说,问题有时仍然会发生。

我有一个四核处理器,通过从 ThreadPool.GetMaxThreads 中减去 ThreadPool.GetAvailableThreads 的结果,我得到 0 个繁忙的工作线程和 1-2 个繁忙的完成端口线程. Process.GetCurrentProcess().Threads.Count 通常返回大约 30。这是一个 Windows 窗体应用程序,虽然它只有一个带菜单的托盘图标,但它从 11 个线程开始。当它达到每分钟发送数千个请求时,它很快就会增加到 30 个。

正如@Noseratio 所建议的,我尝试使用 ThreadPool.SetMinThreadsThreadPool.SetMaxThreads,但它甚至没有改变上面提到的繁忙线程的数量。

最佳答案

当您执行 Task.Run 时,它会使用线程池线程来执行这些任务。当您有长时间运行的任务时,您会导致线程池饥饿,因为它的资源当前被长时间运行的任务占用。

2条建议:

  1. 运行长时间运行的任务时,确保将 Task.Factory.Startnew 与 TaskCreationOptions.LongRunning 结合使用,这将触发新线程的创建。您在这里也必须小心,因为旋转太多新线程会导致过多的上下文切换,从而导致您的应用速度变慢

  2. 在必须执行 IO Bound 工作的地方使用真正的异步,使用支持 TAP 的 api,例如 HttpClient 和 Stream,这不会导致新线程执行阻塞工作。

关于c# - await Task.Delay 花费的时间比预期的要长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23171696/

相关文章:

c# - 部署我的应用程序后,我的用户如何添加 sprite 和图像资源?

c# - 推荐用于在 C# 中处理 xml 配置文件的类?

c# - 在 unity 3d 中检测物体

c# - 在 .NET Framework 3.5 或 4.0 上运行的可执行文件

c# - List<T>.IndexOf() 如何对自定义对象进行比较?

c++ - 在 C++11 中如何使用 std::async with std::launch::any

javascript - 我怎样才能延迟运行一些 JS 代码,直到我的所有异步 JS 文件都下载完毕?

c# - Microsoft.Office.Interop.Word : add caption to image in C#

c# - 在 C# 中使用反射确定参数是否使用 "params"?

java - JAVA 中的“即发即忘”方法,然后您无需等待的方法