Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will a BackgroundService always run in a new Thread

So in the MSDN for ASP.Net Core it shows you how to create Background Tasks with hosted services. There is even a specific paragraph which explains how you can create a Background Queue.

Now my question is, will the ExecuteAsync method run in its own thread already, or do I need to call Task.Run first?

like image 414
Twenty Avatar asked Nov 01 '19 22:11

Twenty


2 Answers

Will a BackgroundService always run in a new Thread? No.

BackgroundService doesn't specify anything about threading. The only thing it asks is for an overload that returns a Task, that remains active as long as the service is up. You can even return a completed task if you want.

If you check the source code you'll see that there's no assumption at all :

    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        _executingTask = ExecuteAsync(_stoppingCts.Token);

        if (_executingTask.IsCompleted)
        {
            return _executingTask;
        }

        return Task.CompletedTask;
    }

The threading behavior of the service method is up to the implementor, ie you. If ExecuteAsync blocks before yielding, the entire service blocks. If the method never yields, the call to StartAsync itself will block and cause problems for the entire application.

If ExecuteAsync does something expensive before the first await, starting other services will be delayed as well.

This means that you may need to use Task.Run if the service needs to do anything expensive before yielding for the first time, ie the first call to await.

like image 95
Panagiotis Kanavos Avatar answered Sep 21 '22 04:09

Panagiotis Kanavos


will the ExecuteAsync method run in its own thread

Presuming ExecuteAsync is an async method (public async Task ExecuteAsync)

Tl;Dr it depdends

async means that this thread can be awaited. await will park the current execution of the main thread until the result of the async returns. This will release the current thread back into the thread pool for re-use. Then when the async returns a new thread (maybe depending on how you actually call this) is pulled out of the thread pool to continue execution. This is called context switching.

If this method is not truly async then nothing really happens, it run as if it's not an async method.

If this method explicitly creates a Task (using Task.Run) then the async thread will await this Task. So the Task uses a new thread and the async method will release it's thread and get a new one when the Task returns. This isn't a zero sum though as the context switching is expensive. This is why you should only async IO bound methods as you typically loose efficiency not gain in CPU bound processes.

I'd suggest you read Stephen Cleary's excellent blogs on the subject

like image 30
Liam Avatar answered Sep 22 '22 04:09

Liam