C# 异步编程 入门学习

本文详细介绍了C#中的异步编程模型,包括异步方法的格式、运行机制,以及如何使用Async和Await关键字实现非阻塞操作。通过实例展示了异步方法在WinForms中的应用,强调了避免阻塞调用方的重要性。
摘要由CSDN通过智能技术生成

C# 异步编程模型 LINK

1. 异步编程的典型场合

在这里插入图片描述

2. 异步方法格式

异步方法旨在成为非阻止操作,异步方法中的 await 表达式在等待的任务正在运行时不会阻止当前线程。
C# 中的 Async 和 Await 关键字是异步编程的核心。
async 和 await 关键字不会创建其他线程。 因为异步方法不会在其自身线程上运行,因此它不需要多线程。

public async Task<int> GetUrlContentLengthAsync()
{
    var client = new HttpClient();

    Task<string> getStringTask =
        client.GetStringAsync("https://learn.microsoft.com/dotnet");

    DoIndependentWork();

    string contents = await getStringTask;

    return contents.Length;
}

void DoIndependentWork()
{
    Console.WriteLine("Working...");
}
  • 方法签名包含 async 修饰符。

  • 按照约定,异步方法的名称以“Async”后缀结尾。(例GetUrlContentLengthAsync)

  • 返回类型为下列类型之一:

    Task<TResult>如果你的方法有操作数为 TResult 类型的返回语句
    Task:如果你的方法没有返回语句或具有没有操作数的返回语句
    void:如果要编写异步事件处理程序
    具有 GetAwaiter 方法的任何其他类型。
    

异步方法通常包含至少一个 await 表达式,该表达式标记一个点,在该点上,直到等待的异步操作完成方法才能继续。 同时,将方法挂起,并且控件返回到方法的调用方(例如winform界面可以响应其它操作)。

3. 异步方法的运行机制

在这里插入图片描述

  • 1 ) 调用方法Calling method 等待 GetUrlContentLengthAsync 异步方法。

  • 2 ) GetUrlContentLengthAsync 创建 HttpClient 实例并调用 GetStringAsync 异步方法以下载网站内容作为字符串。

  • 3 ) GetStringAsync 中发生了某种情况,该情况挂起了它的进程。 可能必须等待网站下载或一些其他阻止活动。 为避免阻止资源,GetStringAsync 会将控制权出让给其调用方 GetUrlContentLengthAsync。

    GetStringAsync 返回 Task<string>,并且 GetUrlContentLengthAsync 将Task分配给 getStringTask 变量。 
    该Task表示调用 GetStringAsync 的正在进行的进程,其中承诺当工作完成时产生实际字符串值。
    
  • 4 ) 由于尚未等待 getStringTask,因此,GetUrlContentLengthAsync 可以继续执行不依赖于 GetStringAsync 得出的最终结果的其他工作

  • 5 ) DoIndependentWork

  • 6 ) GetUrlContentLengthAsync 已运行完毕,可以不受 getStringTask 的结果影响。 接下来,GetUrlContentLengthAsync 需要计算并返回已下载的字符串的长度,但该方法只有在获得字符串的情况下才能计算该值。因此,GetUrlContentLengthAsync 使用一个 await 运算符来挂起其进度,并把控制权交给调用 GetUrlContentLengthAsync 的方法。 GetUrlContentLengthAsync 将 Task 返回给调用方。 该任务表示对产生下载字符串长度的整数结果的一个承诺。
    在Calling method中,处理模式会继续。 在等待结果前,调用方可以开展不依赖于 GetUrlContentLengthAsync 结果的其他工作,否则就需等待片刻。 调用方法等待 GetUrlContentLengthAsync,而 GetUrlContentLengthAsync 等待 GetStringAsync。

  • 7 ) GetStringAsync 完成并生成一个字符串结果。 字符串结果不是通过按你预期的方式调用 GetStringAsync 所返回的。 (记住,该方法已返回步骤 3 中的一个任务)。相反,字符串结果存储在表示 getStringTask 方法完成的任务中。 await 运算符从 getStringTask 中检索结果

  • 8 ) 当 GetUrlContentLengthAsync 具有字符串结果时,该方法可以计算字符串长度。 然后,GetUrlContentLengthAsync 工作也将完成,并且等待事件处理程序可继续使用。

示例 (winform界面)

        private async  void  button11_Click(object sender, EventArgs e)
        {
            var task1 = M1Async();//不会阻塞
            richTextBox1.Text += $"----AAA\n";
            richTextBox1.Text += $"----M3()执行----:end{M3()}\n";//同步方法
            richTextBox1.Text += $"等待task1...(3秒)\n";
            var s1 = await task1;//有返回值
            richTextBox1.Text += $"----task1完成----end:{s1}\n";
            var task2 = M2Async();//不会阻塞
            richTextBox1.Text += $"----BBB\n";
            richTextBox1.Text += $"等待task2...(3秒)\n";
            await task2;//无返回值
            richTextBox1.Text += $"----task2完成\n";
        }
        async Task<string> M1Async()
        {
            await Task.Delay(3000);
            return "M1Async end...";
        }
        async Task M2Async()
        {
            await Task.Delay(3000);
        }
        /*输出=>
        ----AAA
        ----M3()执行----end:M3...
        等待task1...(3秒)
        ----task1完成----:M1Async end...
        ----BBB
        等待task2...(3秒)
        ----task2完成
        */
因为是异步方法,await将控制权出让给button11_Click的调用方Form,界面可以进行其它交互操作。
如果M1Async()是同步方法,此处阻塞,界面点不动,等待M1Async()返回)

//小结:CallingMethod 要标记async,执行到…Async方法时不会阻塞等待其返回结果,而是立即继续执行下一段,直到await,等待…Async方法返回,而且此时控制权交给CallingMethod的调用方。总之尽量不让…Async方法阻塞CallingMethod调用方。

4. await

  • await 指定暂停点,(如果await对象还没完成操作)暂停所属的 async 方法,控制权让给其调用方。 异步操作完成后,await 运算符将返回操作(await对象异步操作)的结果(如果有)。
  • 当 await 运算符应用到表示已完成操作的操作数时(运行到await处时其对象已完成操作),它将立即返回操作的结果,而不会暂停其所属的方法。
  • await 运算符不会阻止计算异步方法的线程。 当 await 运算符暂停其所属的异步方法时,控件将返回到方法的调用方。
  • 异步方法在 await 表达式执行时暂停并不构成方法退出,只会导致 finally 代码块不运行。
  • await t 的操作数 t 通常是:Task、Task<TResult>、ValueTask 或 ValueTask<TResult>。如果表达式 t 的类型为 Task<TResult>ValueTask<TResult>,则表达式 await t 的类型为 TResult。 如果 t 的类型为 Task 或 ValueTask,则 await t 的类型为 void。

5. 返回类型和参数

异步方法通常返回 Task 或 Task <TResult>

如果方法包含指定 TResult 类型操作数的 return 语句,将 Task 指定为返回类型。
如果方法不含任何 return 语句或包含不返回操作数的 return 语句,则将 Task 用作返回类型。

6.BeginInvoke(Delegate)

命名空间: System.Windows.Forms

Invoke 在拥有此控件的基础窗口句柄的线程上执行指定的委托。

BeginInvoke 在创建控件的基础句柄所在线程上异步执行指定委托。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值