简体   繁体   中英

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?

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 await ed. 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

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 .

From Asynchronous programming

For I/O-bound code, you await an operation which returns a Task or Task inside of an async method.

For CPU-bound code, you await an operation which is started on a background thread with the Task.Run method.

So if your ExecuteAsync method is I/O-bound (it looks line it is I/O-bound by its name) then you do not need to call Task.Run

But when the method is CPU-bound (ie your code be performing a computation), then you should call Task.Run to run in background

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