“async Task” vs “return Task.Run”

元气小坏坏 提交于 2020-12-15 06:03:27

问题


I'm new to async/await c# model and trying to understand if these two options are essentially the same thing:

public Task LongRunningMethod()
{
    return Task.Run(async () =>
    {
        await DoStuff();
    });
}

//then call it
await LongRunningMethod();

and this

public async Task LongRunningMethod()
{
    await DoStuff();
}

//then call it
await LongRunningMethod();

I'm thinking the 1st way will use up an extra thread from the pool... And it also wraps a Task into an extra Task. Or am I wrong?


回答1:


Task.Run will queue its delegate to the thread pool. This causes two important things:

  1. Any code in DoStuff before the first asynchronous await will run on a thread pool thread, instead of on the calling thread.
  2. The code in DoStuff will run in a thread pool context, instead of using whatever context was current from the calling thread.

Most of the time, doing asynchronous work in Task.Run is a mistake. But it is sometimes useful, say if DoStuff does some heavy computational work before it acts asynchronously, then Task.Run could be used to move that work off of a UI thread.




回答2:


They are very similar, but there is a chance that DoStuff could complete synchronously; if that happens, your second (await only) method would block for however long that takes, where-as the first (Task.Run) would always return incomplete to the caller (unwinding their stack and scheduling a continuation), and have the blocking work run on the pool thread.

Both options can be desirable, in different scenarios!

However, there is a third option, which expresses exactly the intent of "run the rest somewhere else" as long as you don't have a SyncContext:

public async Task LongRunningMethod()
{
    await Task.Yield();
    await DoStuff(); // possibly with .ConfigureAwait(false)
}

If there is no SyncContext, this is functionally similar to the Task.Run version (meaning: it will always return to the caller as incomplete, and run the DoStuff starting on the pool), just: without the actual Task.Run bits. However, if there is a SyncContext: it will go back onto the same context, which is ... awkward, and unfortunately there is no ConfigureAwait(false) for YieldAwaitable, so in that case you'd have to use Task.Run or similar.




回答3:


The method name conveys the reason why it is done like that, "LongRunning". You can pass a creation flag LongRunning to Task.Run() (which this sample doesn't) and as a pure implementation thread, runtime will allocate a separate thread for that.

Even your second example isn't completely correct, depending on circumstances. If this is a library, then it really should be await DoStuff().ConfigureAwait(false);.



来源:https://stackoverflow.com/questions/62433284/async-task-vs-return-task-run

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!