【问题标题】:What's different between Task.Run(job) and job(); await Task.CompleteTask?Task.Run(job) 和 job(); 之间有什么不同?等待Task.CompleteTask?
【发布时间】:2020-12-05 00:41:34
【问题描述】:

我想做一个同步函数来异步

public JobSync()
{
 // a lot of logic
}

两者

public async JobAsync()
{
 JobSync()
 await Task.CompleteTask;
}

Task.Run(()=>JobSync())

有效,

但是这两种方式有什么区别吗?

【问题讨论】:

  • 第一个将在同一个线程上运行,第二个将创建新线程来运行给定的方法。

标签: c# .net .net-core async-await


【解决方案1】:

我想做一个同步函数来异步

这个版本根本不是异步的:

public async Task JobAsync()
{
    JobSync()
    await Task.CompleteTask;
}

它将完全同步运行,您只需通过 async 关键字添加不必要的开销。

这个版本是“假异步”:

Task.Run(()=>JobSync())

Task.Run 只是在线程池上运行同步代码。但是,它确实会在运行 JobSync 之前返回一个 Task,如果您的目标是 UI 应用程序,这可能会很有用,因为 UI 线程在 JobSync 运行时被释放。

这里真正的问题是为什么你想让JobSync异步,答案是你不应该。

当方法涉及 I/O 时,异步就会发挥作用,因为可以在等待响应的同时释放线程来处理其他工作。

如果JobSync 是一种昂贵的 CPU 密集型方法,会冻结您的 UI,只需使用 Task.Run 调用它:

await Task.Run(JobSync);

根据评论更新

如果您的目标是需要 Task-returning 方法的 API,例如 BackgroundService.ExecuteAsync,那么 Task.FromResult 是最有效的解决方法:

public override Task ExecuteAsync(CancellationToken ct)
{
    return Task.FromResult(JobSync());
}

这只是简单地将JobSync() 的结果放在Task 对象中以满足ExecuteAsync 的要求,但不会不必要地强制代码在线程池上运行。

【讨论】:

  • 谢谢,我用它来适应BackgroundServiceExecuteAsync 方法,我的意思是有时方法签名需要参数是异步的或者需要返回任务
  • 确实如此,这就是Task.FromResult 见上面的更新。
  • 这是否意味着Task.FromResult 将使JobSync() 在专用线程或当前线程上运行?
  • @Panic Task.FromResult 也是一个同步方法,它只是创建一个处于完成状态的Task 对象,并设置它的Result 属性。不会发生线程切换,这正是您想要的,因为它已经在后台运行。
猜你喜欢
  • 2014-05-22
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-21
  • 1970-01-01
相关资源
最近更新 更多