• c# async await


    1.async await

    private void Form2_Load(object sender, EventArgs e)
            {
                Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
                DoSth();  //不加await不等待DoSth执行完成直接先弹出form2_load
                MessageBox.Show("form2_load");
              
            }
    
            async Task DoSth()
            {
                Do1(); //不加await不等待Do1执行完毕(先弹出 DoSth executed after 3s 后弹出 do1 after 5s)相当于并发,加了await就会等待Do1执行完再执行后续相当于阻塞
                await Task.Delay(3000);   //这里不能用Thread.Sleep代替 原因见结尾处红色处文字(如果不开线程则Thread.Sleep会阻塞住主线程 看不到先弹出 DoSth executed after 3s效果)
                Console.WriteLine("dosth:"+Thread.CurrentThread.ManagedThreadId);
                MessageBox.Show("DoSth executed after 3s");
            }
    
            async Task Do1()
            {
                await Task.Delay(5000);//这里不能用Thread.Sleep代替 原因见结尾处红色处文字(如果不开线程则Thread.Sleep会阻塞住主线程 看不到先弹出 DoSth executed after 3s效果)
                Console.WriteLine("do1:"+Thread.CurrentThread.ManagedThreadId);
                MessageBox.Show("do1 after 5s");
            }
    

      

    线程id输出3个都一样 原因(http://www.cnblogs.com/mushroom/p/4575417.html):

    有言论说Async不用开线程,也有说需要开线程的,从单一方面来讲都是对的,也都是错的。 上面源码是从简分析的,具体async内部会涉及到线程上下文切换,线程复用、调度等。 想深入的同学可以研究下ExecutionContextSwitcher、 SecurityContext.RestoreCurrentWI、ExecutionContext这几个东东。

    其实具体的物理线程细节可以不用太关心,知道其【主线程A逻辑->异步任务线程B逻辑->主线程C逻辑】这个基本原理即可。 另外Async也会有线程开销的,所以要合理分业务场景去使用。

    From:http://www.cnblogs.com/xuejianxiyang/p/7089280.html

    以下摘自知乎:

    https://www.zhihu.com/question/30601778

    最近在看《C#图解教程》,其中第20章讲解了.NET 4.5和C# 5.0新添加的异步编程模型async/await,举了一个在GUI中执行异步操作的例子:

    private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
    {
        btnDoStuff.IsEnabled = false;
        lblStatus.Content = "Doing Stuff";
    
        await Task.Delay(4000);
    
        lblStatus.Content = "Not Doing Anything";
        btnDoStuff.IsEnabled = true;
    }
    


    上面这个方法是一个按钮空间Click事件的事件响应代码。

    我的问题是:按照我的理解,控件的响应代码应该是在GUI线程里面被调用的,而且对于GUI应用程序来说,GUI线程一般只有一个,并且所有和GUI控件方面的交互都应该通过GUI线程来完成。那么用await修饰的异步方法是在哪个线程中被调用的?为什么上面这个事件处理方法不会阻塞GUI?
    我还看到其它一些描述是说使用async/await异步模式不会生成新的线程,那么只在原来已有线程的基础上面如何做到异步运行?
    总之,如何正确理解.NET 4.5和C# 5.0中的async/await异步编程模式?

    作者:Ivony
    链接:https://www.zhihu.com/question/30601778/answer/48717630
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    await修饰的方法返回的是一个Task,而这个Task其实就是一个异步句柄,如果我来取名字的话多半就叫做IAsyncHandler。

    一个IAsyncHandler你可以想象成是这么一个东西:
    public interface IAsyncHandler
    {
      Register( Action continuation );
    }
    

    这是伪代码,事实上不存在这么个东西。


    注册一个回调方法在异步操作完成后继续,所以事实上这段代码的原理像是这样的:
    private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
    {
      btnDoStuff.IsEnabled = false;
      lblStatus.Content = "Doing Stuff";
    
      var handler = Task.Delay(4000) as IAsyncHandler
      handler.Register( () =>
      {
        lblStatus.Content = "Not Doing Anything";
        btnDoStuff.IsEnabled = true;
      } );
    }
    

    当然上面全是伪代码,但是如果你能看懂这段代码在干什么,那么async基本就可以懂了,剩下的只是一些实现细节上的问题。


    通常情况下,Task.Delay会立即返回一个Task对象,这个Task对象会在指定时间之后被标记为Completed,而被标记Completed就会立即开一个线程来进行延续的操作。

    但是这里有个问题就是你这个方法是写在UI线程里面的,控件的事件会被UI线程触发,而UI线程上有个SynchronizationContext对象,这个对象的存在就会使得系统在异步回调的时候去捕获源线程。在原来的线程(UI线程)去执行延续的任务。

    而我们知道WinForm里面有个方法叫做Control.Invoke,可以把一个方法封送到UI线程去执行,而上面的工作和这个方法底层的原理其实是一样的,所以,其实这段代码用传统的思维来理解的话像是这样:
    private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
    {
      btnDoStuff.IsEnabled = false;
      lblStatus.Content = "Doing Stuff";
    
      Action continuation = () =>
      {
        lblStatus.Content = "Not Doing Anything";
        btnDoStuff.IsEnabled = true;
      };
    
      Thread.Start( () =>
      {
        Thread.Sleep( 4000 );
        Control.Invoke( continuation );
      } );
    }

    异步并非必然是多线程的,譬如 yield 。

    我举个例子,我显示一串文字,等用户按一下按钮再显示下一串,在第一次显示文字跟用户按下按钮之间,可以做很多事情,这里就是异步的,但不是多线程的。

    有没有办法把两次显示字符串的操作,写在同一个函数里?可以,最简单的方法就是用yield。按钮按下去时候就调用IEnumerator.MoveNext()

    await 本身也不会创造线程,导致出现线程的是后面的那个执行Task 的函数。Task 概念上也不是多线程的,它只是把任务放到了线程池,但是如果任务还没执行,马上需求结果,它就会在当前线程执行,而非在另一个线程来执行。
    所以异步和多线程之间,概念是要分清楚的。

    另外,在F#里面,会有更多的异步模型,只是C#里暂时只能使用Task这个自动挡,让人模糊了概念,只差了一个转身。

     https://bbs.csdn.net/topics/392194509
    实际上
    async Task abc()
    就相当于
    void abc(Action callback)

    async Task<int> abc
    就相当于
    void abc(Action<int> callback)
    ,async/await 语法是让你把异步回调代码用顺序代码的风格来写,但是它也制造了麻烦,使得不求甚解的人会越来越糊涂。

     

    异步实现:

    https://www.cnblogs.com/renjing/p/Invoke.html

  • 相关阅读:
    FastAPI(5)- 查询参数 Query Parameters
    FastAPI(4)- 路径参数 Path Parameters
    FastAPI(3)- uvicorn.run()
    Python
    Python
    Python
    Python
    Python
    Python
    Python
  • 原文地址:https://www.cnblogs.com/xuejianxiyang/p/7089280.html
Copyright © 2020-2023  润新知