Task.Yield(); SyncAction(); 与 Task.Run(()=>SyncAction()); 的区别

6

假设我想要快速地将以下方法异步运行:

ResultType SynchronousCode(ParamType x)
{
     return SomeLongRunningWebRequest(x);
}

以下两个代码示例的执行/调度方式有何区别?
async Task<ResultType> AsynchronousCode(ParamType x)
{
    return await Task.Run(() => SomeLongRunningWebRequest(x));
}

与之相比:

async Task<ResultType> AsynchronousCode(ParamType x)
{
    await Task.Yield();
    return SomeLongRunningWebRequest(x);
}

我理解Task.Yield()的调用将确保线程立即返回给调用者,而Task.Run()肯定会在ThreadPool上安排代码运行,但这两种方法是否有效地使方法异步?假设我们在默认的SynchronizationContext上。

1个回答

7

虽然两种选项都不好,但在 GUI 应用程序中有一个重要的区别:在 Task.Yield 返回后,方法的其余部分将被发送回原始的 SynchronizationContext。如果您从 UI 线程运行它,那么您的长时间运行操作将在 UI 线程上执行,从而冻结它。因此,如果您的意图是避免 UI 阻塞,Task.Yield 将不起作用。使用 Task.Run 不会发生这种情况。


1
那么,如果我们在默认的同步上下文中,就没有任何区别了吗? - Dev2345
1
只要您没有使用奇怪的任务调度程序覆盖默认调度程序...... 是的,我认为可以。 - Scott Chamberlain
3
在默认情况下,我想这不会有任何区别。但我几乎无法想象除了UI应用程序(为避免阻塞)以外,在任何地方你都会以这种方式做。 - Evk
回答这个问题,我想我们需要了解更多关于你试图做什么的信息。但基本上是的,SomeLongRunningWebRequest应该是异步的。也许如果你想并行运行多个这样的请求,并且你绝对没有办法使长时间运行的方法异步 - 你可以使用Task.Run。 - Evk
4
调用Task.Yield()更糟糕,因为你知道它将在后台线程上运行,而另一种方法只有在正确调用时才会在后台线程上运行。两种选项都不好的原因是为同步函数创建异步包装器本来就是反模式,你不应该这样做。如果调用者需要,请让其调用SynchronousCode上的Task.Run() - Scott Chamberlain
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接