一尘不染

您是否必须将Task.Run放入一种使其异步的方法中?

c#

我试图以最简单的形式理解异步等待。为了这个示例,我想创建一个非常简单的方法,将两个数字相加,当然,这根本没有处理时间,这只是在此处举例说明的问题。

例子1

private async Task DoWork1Async()
{
    int result = 1 + 2;
}

例子2

private async Task DoWork2Async()
{
    Task.Run( () =>
    {
        int result = 1 + 2;
    });
}

如果我等待DoWork1Async(),代码将同步还是异步运行?

是否需要包装同步代码Task.Run以使该方法可以等待和异步,以免阻塞UI线程?

我试图弄清楚我的方法是a Task还是return Task<T>,是否需要包装代码Task.Run以使其异步。

我确定是个愚蠢的问题,但我在网上看到的例子是人们在等待没有异步且没有包装在Task.Run或中的代码StartNew


阅读 411

收藏
2020-05-19

共1个答案

一尘不染

首先,让我们澄清一些术语:“异步”(async)表示它可以在启动之前将控制权交还给调用线程。在一种async方法中,那些“屈服”点是await表达式。

这与“异步”一词有很大不同,因为MSDN文档使用(多年来)表示“在后台线程上执行”。

进一步混淆这个问题,async与“等待”有很大不同;有一些async方法的返回类型不可等待,而许多方法的返回类型则不是async

足够了他们 不是 。这里是他们什么

  • 所述async关键字允许异步方法(即,它允许await表达式)。async方法可能会返回TaskTask<T>或(如果必须)void
  • 遵循特定模式的任何类型都是可以等待的。最常见的等待类型是TaskTask<T>

因此,如果我们将您的问题重新表述为“如何以一种可以等待的方式 在后台线程上 运行操作”,答案是使用Task.Run

private Task<int> DoWorkAsync() // No async because the method does not need await
{
  return Task.Run(() =>
  {
    return 1 + 2;
  });
}

(但是这种模式是一种糟糕的方法;请参见下文)。

但是,如果您的问题是“我如何创建一种async可以让其返回给调用者而不是阻塞的方法”,则答案是声明该方法asyncawait用于其“收益”点:

private async Task<int> GetWebPageHtmlSizeAsync()
{
  var client = new HttpClient();
  var html = await client.GetAsync("http://www.example.com/");
  return html.Length;
}

因此,事物的基本模式是使async代码依赖于其await表达式中的“ awaitables”
。这些“等待项”可以是其他async方法,也可以是返回等待项的常规方法。常规方法返回Task/ Task<T>
使用Task.Run到在后台线程执行代码,或(更常见),他们可以用TaskCompletionSource<T>或它的快捷方式(之一TaskFactory.FromAsyncTask.FromResult等等)。我
建议在中包装整个方法Task.Run;同步方法应具有同步签名,是否应将其包装在Task.Run

private int DoWork()
{
  return 1 + 2;
}

private void MoreSynchronousProcessing()
{
  // Execute it directly (synchronously), since we are also a synchronous method.
  var result = DoWork();
  ...
}

private async Task DoVariousThingsFromTheUIThreadAsync()
{
  // I have a bunch of async work to do, and I am executed on the UI thread.
  var result = await Task.Run(() => DoWork());
  ...
}

我的博客上有一个async/ awaitintro;最后是一些很好的后续资源。的MSDN文档async也非常出色。

2020-05-19