首页 > 其他分享 >Csharper Async和Await

Csharper Async和Await

时间:2024-07-25 17:53:05浏览次数:9  
标签:await Console CurrentThread Thread ManagedThreadId Await WriteLine Csharper Asyn

Async和Await的学习

AsyncAwait语法解读

它是一个语法糖:编译器提供的便捷功能
async 是用来修饰方法,如果单独出现,方法会警告,没有什么作用
await在方法体内部,只能放在async修饰的方法内,必须放在task前面
async/await方法里面如果没有返回值,默认返回一个Task,或者void(推荐用Task,而不是void,因为这样才能await/wait)
带async+await后,返回值要多一层Task<>

不使用await/async的代码进行运行

    public static void TestShow()
    {
        Test();
    }


    public static void Test()
    {
        Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
        {
            NoReturnNoAwait();
        }

        Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        Console.Read();
    }

    private static async void NoReturnNoAwait()
    {
        //主线程执行
        Task task = Task.Run(() =>//启动新线程完成任务
        {
            Thread.Sleep(1000);
            Console.WriteLine($"NoReturnNoAwait Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(1000);
            Console.WriteLine($"NoReturnNoAwait Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
        });

        //主线程执行
        Console.WriteLine($"NoReturnNoAwait Sleep after Task,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    }
}

运行后的结果

运行另外一个函数并不适用async:

   public static void Test()
   {
       //Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
       //{
       //     NoReturnNoAwait();
       //}

       {
           Task t = NoReturn();
           t.Wait();//主线程在这里就可以登录
           {
               for (int i = 0; i < 10; i++)
               {
                   Thread.Sleep(300);
                   Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")} i={i}");
               }
           }
       }
}


 private static Task NoReturn()
 {
     //主线程执行
     Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
     TaskFactory taskFactory = new TaskFactory();
     Task task = taskFactory.StartNew(() =>
     {
         Console.WriteLine($"NoReturn Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
         Thread.Sleep(3000);
         Console.WriteLine($"NoReturn Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
     });

     //像什么?continuwith

     //task.ContinueWith(t =>
     //{
     //    Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
     //});

     return task;
}

使用async和await关键字的方法

 public static void Test()
 {
         {
         Task t = NoReturnTask();
         Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
}
}

  private static async Task NoReturnTask() //在async/await方法里面如果没有返回值,默认返回一个Task
  {
      //这里还是主线程的id
      Console.WriteLine($"NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");

      Task task = Task.Run(() =>
      {
          Console.WriteLine($"NoReturnTask Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
          Thread.Sleep(1000);
          Console.WriteLine($"NoReturnTask Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
      });
      await task;
      Console.WriteLine($"NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}

可以观察到我们的代码都是并行的。

  1. await: 线程遇到awai就返回,不阻塞:并发执行
  2. 做到控制顺序
    其实就是以写同步方法 的方式;来完成多线程:--可以控制顺序
  3. 主线程和子线程是并发执行
  4. 有点类似于一个回调
  5. 有async/await 如果没有返回值,就直接返回一个Task

特点:
l. 可以多线程并发执行,可以控制代码的执行顺序一一做到了严格控制代码的执行顺序;
2.执行的特点:当前执行的线程,调用的有asyncawait修饰的函数,且没有await修饰,进入函数后,遇到await,就直接返回执行调用当前函数后面的代码:如果当前调用也用了await修饰,就严格按照顺序执行:不存在遇到await回去继续往后执行:
3.await启动线程的后面的内容,又会启动一个新的线程来继续往后执行;以此往复;

AsyncAwait底层源码解读(状态机)

async和await在底层是一个状态机(状态模式),类似红绿灯,红灯:停,绿灯:行,按照条件执行,像switch

示例代码

 public class AwaitAsyncILSpy
 {
     public static void Show()
     {
         Console.WriteLine($"start1 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
         Async();
         Console.WriteLine($"aaa2 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
     }
     public static async void Async()
     {
         Console.WriteLine($"ddd5 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
         await Task.Run(() =>
         {
             Thread.Sleep(500);
             Console.WriteLine($"bbb3 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
         });
         Console.WriteLine($"ccc4 {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
     }
 }

使用Ilspy反编译以后

看到IL反汇编出来的代码,我们可以知道:

  1. 实例化状态机
  2. 把状态机实例交给一个build去执行
  3. 整理线程的上下文
  4. stateMachine.MoveNext(); 调用MoveNext方法
  5. MoveNext如何执行:先获取一个状态 ---继续往后执行
  6. 如果有异常---一抛出异常--把状态重置为-2
  7. 如果没有异常,把状态重置重置为-2
  8. SetResult();---把结果包裹成一个Tsak

Winform中使用async/await

这里创建一个winform的程序并实现了2个按钮

同步按钮得代码:

 private void btnSync_Click(object sender, EventArgs e)
 {
     Debug.WriteLine($"**********************************btnSync_Click******************************************");
     Debug.WriteLine($"This is btnSync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
     var task = this.CalculationAsync(1_000_000);           
   
     long lResult = task.Result;      

     Debug.WriteLine($"This is btnSync_Click   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");

     this.textSync.Text = lResult.ToString();
 }

异步按钮得代码:

 /// <summary>
 ///异步方法: 正常执行
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private async void btnAsync_Click(object sender, EventArgs e)
 {
     Debug.WriteLine($"**********************************btnAsync_Click******************************************");
     Debug.WriteLine($"This is btnAsync_Click Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");

     long lResult = await this.CalculationAsync(1_000_000);

     Debug.WriteLine($"This is btnAsync_Click   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");

     this.textAsyncResult.Text = lResult.ToString();
  
 }

对应计算得代码:

 private async Task<long> CalculationAsync(long total)
 {
     var task = await Task.Run(() =>
       {
           Debug.WriteLine($"This is CalculationAsync Start,ThreadId={Thread.CurrentThread.ManagedThreadId}");
           long lResult = 0;
           for (int i = 0; i < total; i++)
           {
               lResult += i;
           }
           Debug.WriteLine($"This is CalculationAsync   End,ThreadId={Thread.CurrentThread.ManagedThreadId}");

           return lResult;
       });

     return task; 
 }

当点击同步按钮得时候就会遇到一个问题,程序卡死了,为什么会造成这个问题?

  1. 主线程要等待 Winform特殊设计:await后面的内容必须由主线程执行;
  2. 主线程在这儿也等待着在
  3. 主线程无暇分身导致死锁

更改控件的值,这里必须是(UI线程)主线程去执行;
每次执行都能成功,说明每次这里都是主线程来执行的;
跟Winform设计有关系;在Winform中,await后面的内容,都会让主线程来执行;

因此造成了主线程得死锁。

标签:await,Console,CurrentThread,Thread,ManagedThreadId,Await,WriteLine,Csharper,Asyn
From: https://www.cnblogs.com/wenlong-4613615/p/18252655

相关文章

  • object dict cannot be used in await expression报错解释
    报错解释:这个错误通常出现在使用Python的异步编程模型时,尝试在一个不支持异步的对象上使用await关键字。在Python中,await关键字只能在异步函数中使用,而异步函数通常定义在asyncdef语句中。错误"objectdictcannotbeusedinawaitexpression"意味着你正尝试在一个普通的字典......
  • C#的await,async,task(新手向)
    asyncawaittask首先搞清楚什么是同步什么是异步Synchronize同步asynchronous异步相差也就是一个a,也可以理解为a开头的就是异步操作,同步一般是:当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行异步一般是:方法被调用时立即返回,并获取一个线程执行该方法......
  • 如何立即取消使用 Ollama Python 库生成答案的 Asyncio 任务?
    我正在使用Ollama通过OllamaPythonAPI从大型语言模型(LLM)生成答案。我想通过单击停止按钮取消响应生成。问题在于,只有当响应生成已经开始打印时,任务取消才会起作用。如果任务仍在处理并准备打印,则取消不起作用,并且无论如何都会打印响应。更具体地说,即使单击按钮后,此函数......
  • vue3 await
    在JavaScript中,await是一个用于处理异步操作的关键字。它只能在async函数内部使用,并且用于等待一个Promise对象的解析。在Vue3中,await关键字常用于在组合式API的setup函数中处理异步操作,比如数据获取。使用await的示例以下是一个使用await关键字的简单示例,它......
  • vue3 async 关键字
    async关键字用于声明一个异步函数,这个函数会返回一个Promise对象。与await关键字配合使用时,可以在异步函数中暂停代码执行,直到Promise解决或拒绝,从而使异步代码的处理更简单和同步化。使用async的示例下面是一个完整的Vue3组件示例,展示了如何使用async和await来......
  • async await
    async函数返回值......
  • 使用 useLazyAsyncData 提升数据加载体验
    title:使用useLazyAsyncData提升数据加载体验date:2024/7/19updated:2024/7/19author:cmdragonexcerpt:摘要:本文介绍useLazyAsyncData函数在Nuxt3中的使用,以提升数据加载体验。此函数支持异步获取数据并在组件中处理挂起与错误状态,通过pending、error和data属性实......
  • async sqlalchemy 异步查询
      实体和属性返回多条数据 fetchall()q=select(models.User)result=awaitsession.execute(q)foriinresult:print(i)fetchone()返回一条数据q=select(models.User)result=awaitsession.execute(q)print(result.fetchone())>>>(<model.models.U......
  • asyncio/trio fastdfs python client
    Codets.py#!/usr/bin/envpython"""FastDFS并发测试脚本Usage::$python<me>.py200--show"""importfunctoolsimportitertoolsimportjsonimportosimportpickleimportsysimporttimefrompathlibimportPathfr......
  • 轻松掌握useAsyncData获取异步数据
    title:轻松掌握useAsyncData获取异步数据date:2024/7/12updated:2024/7/12author:cmdragonexcerpt:摘要:本文详细介绍Nuxt.js中的useAsyncData组合式函数,它用于在服务端渲染(SSR)过程中异步获取数据,确保客户端正确水合,避免重复请求。内容包括基本概念、参数说明(key,ha......