C# -- Async 和 Await 解惑

1. Async 官方文档上的解释

关于C#

我觉得最下面关于 await 在文档上的理解比较好,^^

使用 async 修饰符可将方法、lambda 表达式或匿名方法指定为异步。 如果用在方法或表达式使用此修饰符,则其称为异步方法

public async Task<int> ExampleMethodAsync()  
{  
    // . . . .  
} 

an async method uses the await keyword to do pentially long-running work without blocking the caller’s thread

长时间运行的工作而不会阻塞调用方的线程

string contents = await contentsTask; 

Async modify 方法将同步运行直至到达其第一个 await 表达式,此时会将方法挂起,直到等待的任务完成。 同时,如下节示例中所示,控件将返回到方法的调用方

如果 async 关键字修改的方法不包含 await 表达式或语句,则该方法将同步执行。 编译器警告将通知你不包含 await 的任何异步方法,因为该情况可能表示存在错误

async 关键字是上下文关键字,原因在于只有当它修饰方法、lambda 表达式或匿名方法时,它才是关键字。 在所有其他上下文中,都会将其解释为标识符

1.1 Example (想运行看最上面链接)

The following example shows the structure and flow of control between

  • an async event handler

  • StartButton_Click

  • and an async method

  • ExampleMethodAsync

private async void StartButton_Click(object sender, RoutedEventArgs e)
{
    // ExampleMethodAsync returns a Task<int>, which means that the method eventually produces an int result. 
    //However, ExampleMethodAsync returns the Task<int> value as soon as it reaches an await.  
    ResultsTextBox.Text += "\n";
    try
    {
        int length = await ExampleMethodAsync();
        // Note that you could put "await ExampleMethodAsync()" in the next line where  
        // "length" is, but due to when '+=' fetches the value of ResultsTextBox, you  
        // would not see the global side effect of ExampleMethodAsync setting the text.  
        ResultsTextBox.Text += String.Format("Length: {0}\n", length);
    }
    catch (Exception)
    {
        // Process the exception if one occurs.  
    }
}

public async Task<int> ExampleMethodAsync()
{
    var httpClient = new HttpClient();
    int exampleInt = (await httpClient.GetStringAsync("http://msdn.microsoft.com")).Length;
    ResultsTextBox.Text += "Preparing to finish ExampleMethodAsync.\n";
    // After the following return statement, any method that's awaiting  
    // ExampleMethodAsync (in this case, StartButton_Click) can get the   
    // integer result.  
    return exampleInt;
}
// Output:  
// Preparing to finish ExampleMethodAsync.  
// Length: 53292  

1.2. 返回类型

异步方法的返回类型可以为 Task、Task 或 void。 方法不能声明任何 ref 或 out 参数,但是可以调用具有这类参数的方法。

如果异步方法的返回语句指定一个 TResult 类型的操作数,则你应指定 Task 作为方法的返回类型。 如果当方法完成时未返回有意义的值,则应使用 Task。 即,对方法的调用将返回一个 Task,但是当 Task 完成时,任何等待 Task 的所有 await 表达式的计算结果都为 void。

你应主要使用 void 返回类型来定义事件处理程序,这些处理程序需要此返回类型。 void 返回异步方法的调用方不能等待,并且无法捕获该方法引发的异常

2. Await

await 运算符在异步方法应用于任务,以挂起执行方法,直到所等待的任务完成。挂起在下面解释, 任务表示正在进行的工作

使用 await 的异步方法必须被async 关键字修饰。 使用 async 修饰符定义并且通常包含一个或多个 await 表达式的这类方法称为异步方法

应用 await 运算符的任务通常是实现基于任务的异步模式的方法调用的返回值。 示例包括 Task 或 Task 类型的值

2.1 await 返回类型

如果 await 应用于返回 Task<TResult> 的方法调用结果,则 await 表达式的类型为 TResult。 如果 await 应用于返回 Task 的方法调用结果,则 await 表达式的类型为 void。 以下示例演示了差异

// Keyword await used with a method that returns a Task<TResult>.  
TResult result = await AsyncMethodThatReturnsTaskTResult();  

// Keyword await used with a method that returns a Task.  
await AsyncMethodThatReturnsTask();  

await 表达式不阻止正在执行它的线程(简单理解为主线程)。 而是使编译器将剩下的异步方法注册为等待任务的延续任务。 控制权随后会返回给异步方法的调用方。 任务完成时(谁执行任务?挂起的又是谁?主线程;执行完任务的主线程(此时异步任务没结束,所以要刮起等待结果)),它会调用其延续任务,异步方法的执行会在暂停的位置处恢复。

await 表达式只能在由 async 修饰符标记的立即封闭方法体( the body of an immediately enclosing method)、lambda 表达式或异步方法中出现。 术语“await”在该上下文中仅用作关键字。 在其他位置,它会解释为标识符。 在方法、lambda 表达式或匿名方法中,await 表达式不能在同步函数体、查询表达式、lock 语句块或不安全上下文中出现

这里写图片描述

关于文档上关于 await 让我困惑很久的一段话

An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task

await 表达式不阻止正在执行它的线程(简单理解为主线程)。 而是使编译器将剩下的异步方法(主线程结束后还在执行的异步线程)注册为等待任务的延续任务。 控制权随后会返回给异步方法的调用方。 任务完成时,它会调用其延续任务,异步方法的执行会在暂停的位置处恢复

3. 官方图解

这里写图片描述

4. 放码过来

class Program
    {
        async Task<int> AccessTheWebAsync()
        {
            HttpClient client = new HttpClient();

            Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

            DoIndependentWork();

            string urlContents = await getStringTask;

            Console.WriteLine("---------------"+urlContents.Length);
            return urlContents.Length;
        }

        void DoIndependentWork()
        {
            Console.WriteLine("----------");
        }
        static void Main(string[] args)
        {
            Program pr = new Program();
            Task<int> my = pr.AccessTheWebAsync();
            Console.WriteLine(my.Result);
            Console.ReadLine();
        }
    }

可以运行的,就是懒

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值