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

本文翻译自:Do you have to put Task.Run in a method to make it async?

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. 为了这个示例,我想创建一个非常简单的方法,将两个数字相加,当然,这根本不需要处理时间,这只是在此处举例说明的问题。

Example 1 例子1

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

Example 2 例子2

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

If I await DoWork1Async() will the code run synchronously or asynchronously? 如果我等待DoWork1Async() ,代码将同步还是异步运行?

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.Run包装同步代码,以使该方法可以等待且异步,以免阻塞UI线程?

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还是返回Task<T> ,是否需要用Task.Run包装代码以使其异步。

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 . 我确定是愚蠢的问题,但我在网上看到的示例中,人们正在等待没有异步且没有包装在Task.RunStartNew


#1楼

参考:https://stackoom.com/question/19Ps7/您是否必须将Task-Run放入一种使其异步的方法中


#2楼

First, let's clear up some terminology: "asynchronous" ( async ) means that it may yield control back to the calling thread before it starts. 首先,让我们澄清一些术语:“异步”( async )表示它可以在启动之前将控制权交还给调用线程。 In an async method, those "yield" points are await expressions. async方法中,那些“屈服”点是await表达式。

This is very different than the term "asynchronous", as (mis)used by the MSDN documentation for years to mean "executes on a background thread". 这与“异步”一词有很大不同,因为MSDN文档使用(多年来)表示“在后台线程上执行”。

To futher confuse the issue, async is very different than "awaitable"; 为了进一步混淆这个问题, async与“ awaitable”有很大的不同。 there are some async methods whose return types are not awaitable, and many methods returning awaitable types that are not async . 有一些async方法的返回类型不可等待,许多方法返回的等待类型不是async

Enough about what they aren't ; 足够了他们不是 here's what they are : 这里是它们什么:

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

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 : 因此,如果我们将您的问题重新表述为“如何以一种可以等待的方式在后台线程上运行操作”,答案是使用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). (但是这种模式是一种糟糕的方法;请参见下文)。

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: 但是,如果您的问题是“我如何创建一个async方法,该方法可以让其返回给调用者而不是阻止它”,答案是将方法声明为async并在其“屈服”点上使用await

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

So, the basic pattern of things is to have async code depend on "awaitables" in its await expressions. 因此,事物的基本模式是使async代码依赖于其await表达式中的“ awaitables”。 These "awaitables" can be other async methods or just regular methods returning awaitables. 这些“ awaitables”可以是其他async方法,也可以是返回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). 返回Task / Task<T>常规方法可以使用Task.Run在后台线程上执行代码,或者(通常)可以使用TaskCompletionSource<T>或其快捷方式之一( TaskFactory.FromAsyncTask.FromResult等)。 。 I don't recommend wrapping an entire method in Task.Run ; 建议在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 : 同步方法应具有同步签名,是否应将其包装在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());
  ...
}

I have an async / await intro on my blog; 我的博客上有一个async / await介绍 at the end are some good followup resources. 最后是一些很好的后续资源。 The MSDN docs for async are unusually good, too. async的MSDN文档也非常好。


#3楼

One of the most important thing to remember when decorating a method with async is that at least there is one await operator inside the method. 异步装饰方法时要记住的最重要的事情之一是,方法内部至少有一个 await运算符。 In your example, I would translate it as shown below using TaskCompletionSource . 在您的示例中,我将使用TaskCompletionSource如下所示进行翻译

private Task<int> DoWorkAsync()
{
    //create a task completion source
    //the type of the result value must be the same
    //as the type in the returning Task
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    Task.Run(() =>
    {
        int result = 1 + 2;
        //set the result to TaskCompletionSource
        tcs.SetResult(result);
    });
    //return the Task
    return tcs.Task;
}

private async void DoWork()
{
    int result = await DoWorkAsync();
}

#4楼

When you use Task.Run to run a method, Task gets a thread from threadpool to run that method. 当您使用Task.Run运行方法时,Task从线程池获取一个线程来运行该方法。 So from the UI thread's perspective, it is "asynchronous" as it doesn't block UI thread.This is fine for desktop application as you usually don't need many threads to take care of user interactions. 因此,从UI线程的角度来看,它是“异步的”,因为它不会阻止UI线程。这对于桌面应用程序来说很好,因为您通常不需要很多线程来处理用户交互。

However, for web application each request is serviced by a thread-pool thread and thus the number of active requests can be increased by saving such threads. 但是,对于Web应用程序,每个请求都由线程池线程服务,因此可以通过保存此类线程来增加活动请求的数量。 Frequently using threadpool threads to simulate async operation is not scalable for web applications. 对于Web应用程序,经常使用线程池线程来模拟异步操作无法扩展。

True Async doesn't necessarily involving using a thread for I/O operations, such as file / DB access etc. You can read this to understand why I/O operation doesn't need threads. True Async不一定涉及使用线程进行I / O操作,例如文件/数据库访问等。您可以阅读此书以了解为什么I / O操作不需要线程。 http://blog.stephencleary.com/2013/11/there-is-no-thread.html http://blog.stephencleary.com/2013/11/there-is-no-thread.html

In your simple example,it is a pure CPU-bound calculation, so using Task.Run is fine. 在您的简单示例中,它是纯CPU限制的计算,因此使用Task.Run很好。


#5楼

Very good explanation when and how to use Task.Run and await 何时以及如何使用Task.Runawait的很好的解释

Using Task.Run in Conjunction with Async/Await 将Task.Run与Async / Await结合使用

Advanced Tips for Using Task.Run With Async/Await 使用Task.Run和Async / Await的高级技巧

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值