【问题标题】:async pattern in a top-level worker method顶级工作方法中的异步模式
【发布时间】:2018-02-28 17:57:52
【问题描述】:

我们在网络角色中有一些工作线程。它是在OnStart 方法中创建的

Task.Factory.StartNew(() => DoWorkAsync(), TaskCreationOptions.LongRunning);

然后DoWorkAsync 方法将继续轮询队列并做一些耗时的工作。实际工作需要几分钟,因为它提交查询作业并等待结果返回。这些函数采用async 模式。实现顶级DoWorkAsync 方法的正确方法是什么?如果我执行以下操作,那么这里有点阻塞,并且只调用了一个PollingQueueAndWorkAsync()

public async void DoWorkAsync()
{
  while (_continue)
  {
    await PollingQueueAndWorkAsync();
  }
}

还是以下?它看起来不正确,因为它一直在不同的线程中运行该方法。

public async void DoWorkAsync()
{
  while (_continue)
  {
    Task.Run(() => PollingQueueAndWorkAsync());
  }
}

我正在尝试将代码重构为“一直异步”。但是在顶级worker方法中应该如何结束呢?

[更新]

在尝试更多之后,这是我所拥有的:

public async void DoWorkAsync()
{
  while (_continue)
  {
    Task.Run(async () => await PollingQueueAndWorkAsync());
  }
}

行为是我想要的,因为新消息不断添加到队列中,这个循环可以处理队列中的消息。然而,在运行一段时间后,它会抛出我们的内存异常。是因为它创造了太多的延续吗?所以我应该使用 SemaphoreSlim 来限制任务数量?

【问题讨论】:

标签: c# multithreading asynchronous task-parallel-library async-await


【解决方案1】:

我通常不鼓励在 ASP.NET 中执行与请求无关的代码。但是,如果它是作为独立工作者精心编写的(听起来确实如此),那么您可以使用我博客中的BackgroundTaskManager type

BackgroundTaskManager 理解同步和异步任务,并且这些任务在 ASP.NET 运行时中注册,以最大限度地减少循环意外终止它们的机会。此外,该类型公开了一个名为BackgroundTaskManager.ShutdownCancellationToken,您的PollingQueueAndWorkAsync 可以使用它来检测它何时应该干净地退出。

【讨论】:

  • 我已更新我的帖子以添加另一个选项。我的问题是 Task.Run(async () => await PollingQueueAndWorkAsync());是不是意味着它一直在一个线程池线程上运行 PollingQueueAndWorkAsync,当它运行到底层的 await 时,然后这个线程池线程返回到池中?
  • 是的,Task.Run 将在线程池线程上执行,当您的方法等待线程时,该线程将返回到池中。
【解决方案2】:

你应该像这样创建你的投票线程:

public async void DoWorkAsync()
{
    await Task.Run(() => PollingQueueAndWorkAsync());
}

然后你应该在线程本身中检查'_continue',以便在工作被取消时它们可以干净地退出。

【讨论】:

  • 但是我希望 DoWorkAsync 继续运行,因为新消息一直在添加到队列中,并且 DoWorkAsync 需要继续处理它们。
猜你喜欢
  • 1970-01-01
  • 2019-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
相关资源
最近更新 更多