【问题标题】:Task.Run(method group) vs. Task.Run(lambda)Task.Run(方法组)与 Task.Run(lambda)
【发布时间】:2019-07-23 02:24:17
【问题描述】:

我需要知道这三种使用 TPL 启动任务的方式之间的区别:

Task.Run(() => _client.RunClient());

对比

Task.Run(_client.RunClient);

对比

Task.Run(async () => await _client.RunClient());

假设我有以下类结构:

public class Controller {

  private _client = new Client();

  ...

  public async Task StartClientA() {
    await Task.Run(_client.RunClient);
  }

  public async Task StartClientB() {
    await Task.Run(() => _client.RunClient());
  }

  public async Task StartClientC() {
    await Task.Run(async () => await _client.RunClient());
  }
}

那么,在客户端,下面是 StartClientA、StartClientB 和 StartClientC 的方法签名:

public async Task StartClientA() {
  ...
}

public async Task StartClientB() {
  ...
}

public async Task StartClientC() {
  ...
}

现在,我在这些方法中调用 RunClient 的方式有什么区别?

让我感到困惑的是后面的代码会发生什么:

await Task.Run(...)

Task.Run 是否立即返回,并且函数继续执行?还是仅在方法 _client.RunClient 完成时才完成 Task.Run?什么是 _client.RunClient 在一个 while(true) 循环中并且从不退出?这对这些启动线程的方法有何影响?

围绕这些不同的任务调用方式的最佳实践是什么?我要等待 lambda 吗?我要等待 Task.Run 吗?我不等待_client.RunClient 吗?

对于一篇帖子中的所有问题,我们深表歉意。我试图了解这些不同的行为,以便我可以选择最有意义的一种。我读过很多关于 async/await 的文章,这是一个我似乎找不到答案的问题。

提前感谢您的帮助。

【问题讨论】:

    标签: .net asynchronous lambda async-await task-parallel-library


    【解决方案1】:

    我需要知道这三种启动任务的方式之间的区别

    Task.Run(() => _client.RunClient());
    Task.Run(_client.RunClient);
    Task.Run(async () => await _client.RunClient());
    

    这些都差不多。第一个传入一个 lambda,它被转换为一个委托;第二个传入一个方法组,该方法组被转换为委托;第三个传入一个 lambda,它被转换为一个具有async 状态机的委托。

    但就语义而言,它们实际上都是相同的。第三个的开销稍大一些,但很可能在您的实际应用程序中开销非常小。

    Task.Run 是否立即返回,函数继续执行?

    Task.Run 立即返回Task

    或者Task.Run只有在_client.RunClient方法完成时才完成?

    这取决于Task.Run 完成的含义。它立即返回一个任务,但是当一个方法返回一个任务时,该任务代表该方法的执行。 Task.Run 返回的任务将在 RunClient 完成时完成。

    什么是 _client.RunClient 在一个 while(true) 循环中并且从不退出?这对这些启动线程的方法有何影响?

    那么Task.Run返回的任务永远不会完成。

    围绕这些不同的任务调用方式的最佳实践是什么?我要等待 lambda 吗?我要等待 Task.Run 吗?我不等待 _client.RunClient 吗?

    1. await 任务。除非你不应该(例如,任务没有完成)。
    2. Don't use Task.Run。除非您需要(例如,将 CPU 绑定代码移出 UI 线程,或强制执行线程池上下文)。
    3. 不要elide async and await。除非它是一个简单的方法,比如本例中的 lambda。

    【讨论】:

    • 谢谢斯蒂芬。感谢您的彻底回应。
    猜你喜欢
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 2018-12-09
    • 2020-04-18
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    相关资源
    最近更新 更多