您是否必须将 Task.Run 放在一个方法中以使其异步? [英] Do you have to put Task.Run in a method to make it async?

查看:29
本文介绍了您是否必须将 Task.Run 放在一个方法中以使其异步?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to understand async await in the simplest form. I want to create a very simple method that adds two numbers for the sake of this example, granted, it's no processing time at all, it's just a matter of formulating an example here.

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

示例 2

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

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

If I await DoWork1Async() will the code run synchronously or asynchronously?

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

Do I need to wrap the sync code with Task.Run to make the method awaitable AND asynchronous so as not to block the UI thread?

我想弄清楚我的方法是 Task 还是返回 Task 我是否需要用 Task.Run 包装代码 使其异步.

I'm trying to figure out if my method is a Task or returns Task<T> do I need to wrap the code with Task.Run to make it asynchronous.

愚蠢的问题我敢肯定,但我在网上看到一些例子,人们正在等待代码中没有任何异步内容并且没有包含在 Task.RunStartNew 中.

Stupid question I'm sure but I see examples on the net where people are awaiting code that has nothing async within and not wrapped in a Task.Run or StartNew.

推荐答案

首先,让我们澄清一些术语:异步"(async)意味着它可能会在之前将控制权交还给调用线程开始.在 async 方法中,那些yield"点是 await 表达式.

First, let's clear up some terminology: "asynchronous" (async) means that it may yield control back to the calling thread before it starts. In an async method, those "yield" points are await expressions.

这与术语异步"非常不同,因为 MSDN 文档多年来(错误地)使用它来表示在后台线程上执行".

This is very different than the term "asynchronous", as (mis)used by the MSDN documentation for years to mean "executes on a background thread".

为了进一步混淆这个问题,async 与awaitable"非常不同;有一些 async 方法的返回类型是不可等待的,而许多方法返回的可等待类型不是 async.

To futher confuse the issue, async is very different than "awaitable"; there are some async methods whose return types are not awaitable, and many methods returning awaitable types that are not async.

足够了解他们不是什么;这是它们:

Enough about what they aren't; here's what they are:

  • async 关键字允许异步方法(即,它允许 await 表达式).async 方法可能返回 TaskTask 或(如果必须)void.
  • 任何遵循特定模式的类型都可以等待.最常见的等待类型是 TaskTask.
  • The async keyword allows an asynchronous method (that is, it allows await expressions). async methods may return Task, Task<T>, or (if you must) void.
  • Any type that follows a certain pattern can be awaitable. The most common awaitable types are Task and Task<T>.

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

So, if we reformulate your question to "how can I run an operation on a background thread in a way that it's awaitable", the answer is to use Task.Run:

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

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

(But this pattern is a poor approach; see below).

但如果您的问题是我如何创建一个 async 方法,它可以返回给它的调用者而不是阻塞",答案是声明方法 async并使用 await 作为它的屈服"点:

But if your question is "how do I create an async method that can yield back to its caller instead of blocking", the answer is to declare the method async and use await for its "yielding" points:

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

因此,事物的基本模式是让 async 代码依赖于其 await 表达式中的awaitables".这些awaitables"可以是其他async 方法或只是返回awaitables 的常规方法.常规方法返回 Task/Task 可以 使用 Task.Run 在后台线程上执行代码,或者(更常见)他们可以使用 TaskCompletionSource 或其快捷方式之一(TaskFactory.FromAsyncTask.FromResult 等).我建议在 Task.Run 中包装整个方法;同步方法应该有同步签名,是否应该包装在 Task.Run 中应该由消费者决定:

So, the basic pattern of things is to have async code depend on "awaitables" in its await expressions. These "awaitables" can be other async methods or just regular methods returning awaitables. Regular methods returning Task/Task<T> can use Task.Run to execute code on a background thread, or (more commonly) they can use TaskCompletionSource<T> or one of its shortcuts (TaskFactory.FromAsync, Task.FromResult, etc). I don't recommend wrapping an entire method in Task.Run; synchronous methods should have synchronous signatures, and it should be left up to the consumer whether it should be wrapped in a 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/等待介绍在我的博客上;最后是一些很好的后续资源.async 的 MSDN 文档也异常出色.

I have an async/await intro on my blog; at the end are some good followup resources. The MSDN docs for async are unusually good, too.

这篇关于您是否必须将 Task.Run 放在一个方法中以使其异步?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆