简体   繁体   中英

How can I convert this long-running background task to async/await?

I have code that is kicking off work on a long-running background task with a heartbeat. The application is being updated to use async/await and I am having problems updating this code to follow suite. Here is the code, roughly:

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);
}

And here is how the long-running tasks are being started:

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);
    }
}

From what I understand I need to:

  • pass a Func<Task> to CreateAndStartLongRunningTask
  • change StartNew to take async () => await taskFunc() instead of action
  • add async/awaits up through the method signatures as needed

What would be the correct way to get this code runs on a background thread and allows for the async/await pattern?

Essentially in short unless you specifically need it you shouldn't use Task.Factory.StartNew or TaskCreationOptions.LongRunning . Just use Task.Run like so:

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

    }
}, token);

These two articles are helpful in explaining why: http://blog.i3arnon.com/2015/07/02/task-run-long-running/ and https://sergeyteplyakov.github.io/Blog/async/2019/05/21/The-Dangers-of-Task.Factory.StartNew.html

The application is being updated to use async/await

That does not mean everything should become async. If it is a candidate depends on how it interacts with callers and callees. You did not post any of that.

You can (should) probably leave it as-is.

Otoh, a loop with a delay is always suspect. Why not run this on a Timer?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM