C# 异步编程

C# 异步编程需要asyncawait关键字来进行支持。异步编程主要应用在两种模式下:

  • 当程序有 IO 瓶颈时:如访问数据库、读写文件系统或者处理网络请求时,IO都是程序运行的主要瓶颈。
  • 当程序有CPU性能瓶颈时:如进行大量复杂的运算,此时程序的瓶颈在于CPU的性能上。

两种模式下对应的异步编程:
1. 有IO限制的代码:需要在async方法里面 await一个返回TaskTask<T>的线程。该方法不需要使用Task.Run

// 如点击Button获取指定网站上字符内容的长度,为了不阻塞UI需要将获取处理单独放在一个线程。
private async Task<int> GetLengthAsync()
{
    var client = new HttpClient();

    Task<string> GetStrTask = client.GetStringAsync("https://docs.microsoft.com/dotnet");
    Console.WriteLine("Wroking....");

    string resStr = await GetStrTask;
    //或者合在一起的写法:
    //string resStr = await client.GetStringAsync("https://docs.microsoft.com/dotnet");

    return resStr.Length;
}

// 在UI上点击Button后,对应响应函数可以为Lambda匿名函数或者非匿名函数
// 1. Lambda 匿名函数方式
btn.Click += async (s, e) =>
{
    int len = await GetLengthAsync();

    txt03.Text = "Complete the work. result  = " + len;
};

// 2. 非匿名函数方式
btn.Click += BtnClicked;
private async void BtnClicked(object sender, RoutedEventArgs e)
{
    int len = await GetLengthAsync();

    txt03.Text = "Complete the work. result  = " + len;
}

  • 异步方法返回Task<string>意味着在await该Task时,将会返回一个string内容。
  • 在等待任务返回结果之前,程序可以做其它的不依赖于该任务结果的事情。
  • 异步函数GetLengthAsync()的执行流程及await关键字的注意事项:
    • await会让 GetLengthAsync()函数暂时挂起,以等待client.GetStringAsync()返回结果,
      在此之前GetLengthAsync()函数不会继续向下执行。因此异步函数只在出现await关键字的地方挂起等待。
    • 同时会将控制权交还给调用GetLengthAsync()的函数。
    • client.GetStringAsync()函数执行结束,控制权将重新回到该处。
    • 然后 await操作符将从GetStrTask中获取string 内容。

2. 有CPU性能限制的代码:需要使用await Task.Run来在后台执行相应的操作,以保证不会阻塞主线程。

private async Task RunAsync()
{
    await Task.Run(() =>
    {
        int sum = 0;
        for (int i = 0; i < 100000000; ++i)
        {
            sum += i;
        }

        Console.WriteLine("The result is {0}", sum);
    });

}

异步方法的总结

  1. 异步函数声明时需要包含async关键字
  2. 异步方法的命名通常后缀为 Async
  3. 其返回值一般有以下几种形式:
    • Task:方法没有返回值。
    • Task<T>:返回值类型为T
    • void: 异步事件处理方法
    • Lambda表达式时,不在此范围。
  4. 异步方法中通常包含至少一个await 的表达式,表明在此处该函数将不再继续执行,直到await处的异步操作结束为止。
    在此期间,该函数被挂起,且控制权返回给调用者。await关键字相当于告诉异步函数在此进行等候,等待await后面的表达式执行结束后,异步函数再获得控制权并继续向下执行。
  5. 同步方法在运行结束之后直接返回,而异步方法在挂起时会返回一个task,当异步的方法最终结束之后,返回的task会被标注完成,如果有返回值的话会被存储在task中。
  6. 异步编程中调用的API,其后缀都是Async,表示异步方法,需要配合async,await来使用。
  7. 异步编程中控制权如何在方法之间进行流转,如下图所示:

参考资料:
Asynchronous programming

posted @ 2022-05-18 18:09  Jeffxue  阅读(209)  评论(0编辑  收藏  举报