【问题标题】:How can I convert this long-running background task to async/await?如何将此长时间运行的后台任务转换为异步/等待?
【发布时间】:2019-05-29 10:58:30
【问题描述】:

我的代码正在启动一个带有心跳的长时间运行的后台任务。该应用程序正在更新以使用 async/await,我在更新此代码以遵循套件时遇到问题。大致代码如下:

private void StartBackgroundTasks(CancellationTokenSource cancelTokenSrc)
{
    void TaskAction()
    {
        DoWork();
    }

    void HeartbeatAction()
    {
        var task = TaskFactory.CreateAndStartLongRunningTask(
            TaskAction, cancelTokenSrc.Token);

        while (true)
        {
            // checks Task.Status to figure out when to stop
            if (!TryPerformHeartbeat(task)) break;

            Task.Delay(TimeSpan.FromSeconds(20)).Wait();
        }
    }

    TaskFactory.CreateAndStartLongRunningTask(HeartbeatAction);
}

以下是长时间运行的任务的启动方式:

internal static class TaskFactory
{
    internal static Task CreateAndStartLongRunningTask(
        Action action, CancellationToken? token = null)
    {
        return Task.Factory.StartNew(
            action,
            token ?? CancellationToken.None,
            TaskCreationOptions.LongRunning,
            TaskScheduler.Default);
    }
}

据我了解,我需要:

  • Func<Task> 传递给CreateAndStartLongRunningTask
  • StartNew 更改为async () => await taskFunc() 而不是action
  • 根据需要通过方法签名添加异步/等待

让这段代码在后台线程上运行并允许异步/等待模式的正确方法是什么?

【问题讨论】:

    标签: c# async-await


    【解决方案1】:

    简而言之,除非您特别需要它,否则您不应使用Task.Factory.StartNewTaskCreationOptions.LongRunning。只需像这样使用Task.Run

    var task = Task.Run(async () =>
    {
        while (true)
        {
            await TryPerformHeartbeat();
            await Task.Delay(TimeSpan.FromSeconds(20));
    
        }
    }, token);
    

    这两篇文章有助于解释原因: http://blog.i3arnon.com/2015/07/02/task-run-long-running/https://sergeyteplyakov.github.io/Blog/async/2019/05/21/The-Dangers-of-Task.Factory.StartNew.html

    【讨论】:

    • 好答案。旁注:在这里传递token 是没用的;它在原始代码中也没有用。
    • @StephenCleary 您能否提供更多有关令牌为何/无用的信息?发布的代码不完整,如果长时间运行的逻辑协同使用,令牌用于提供超时和/或取消。
    • @yenta:将令牌 传递给 Task.Run 是没有用的,因为它只会取消任务的启动,该任务会立即启动。将其传递给您的内部代表是合适的。
    • 你可以做的是在每次延迟之前检查令牌是否被取消,然后突破 while(true)
    • @StephenCleary 哈哈,现在我明白了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-08
    • 2012-11-15
    相关资源
    最近更新 更多