• async和await详解


     async和await详解

     1.非UI线程中执行

    Test()函数带有async 和await ,返回值写成Task。
     1 using System;
     2 using System.Threading;
     3 using System.Threading.Tasks;
     4 
     5 namespace _00_测试
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
    12             Task task = Test();
    13             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
    14             Console.ReadKey();
    15         }
    16         private async static Task Test()
    17         {
    18             Console.WriteLine($"当前主线程ID::{Thread.CurrentThread.ManagedThreadId}");
    19             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    20             Task task1 = Task.Factory.StartNew(() =>
    21             {
    22                 Thread.Sleep(100);
    23                 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}");
    24                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    25             });
    26             await task1;
    27 
    28             Console.WriteLine($"task1 结束后的线程ID:{Thread.CurrentThread.ManagedThreadId}");
    29             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    30 
    31             await Task.Run(() =>
    32             {
    33                 Thread.Sleep(100);
    34                 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}");
    35                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    36             });
    37             Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}");
    38             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    39         }
    40     }
    41 }

     

     上面是控制台应用程序,主线程的ID为1,第一个await和后面的代码都是子线程完成的。第二个await和后面的代码,也是子线程完成的。在非UI线程中执行的async异步方法,await等待的异步操作和后面要执行的代码,都是从线程池获取一个线程来执行的。

    2.UI线程中执行

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading;
     9 using System.Threading.Tasks;
    10 using System.Windows.Forms;
    11 
    12 namespace _009__数据库
    13 {
    14     public partial class Form1 : Form
    15     {
    16         public Form1()
    17         {
    18             InitializeComponent();
    19         }
    20 
    21         private async void button1_Click(object sender, EventArgs e)
    22         {
    23             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
    24             Task task = Test();
    25             await task;
    26             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
    27             Console.ReadKey();
    28         }
    29         private async static Task Test()
    30         {
    31             Console.WriteLine($"当前主线程ID::{Thread.CurrentThread.ManagedThreadId}");
    32             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    33             Task task1 = Task.Factory.StartNew(() =>
    34             {
    35                 Thread.Sleep(100);
    36                 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}");
    37                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    38             });
    39             await task1;
    40 
    41             Console.WriteLine($"task1 结束后的线程ID:{Thread.CurrentThread.ManagedThreadId}");
    42             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    43 
    44             await Task.Run(() =>
    45             {
    46                 Thread.Sleep(100);
    47                 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}");
    48                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    49             });
    50             Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}");
    51             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
    52         }
    53     }
    54 }

     在UI线程中,async切换线程的规律和非UI线程不一样了。在UI线程中,await后面紧跟的代码,一直都是在UI线程中执行的。

    注意:非UI线程中,await后面的动作都是子线程完成的;UI线程中,await后面的动作都是主线程完成的。

    3.带返回值的异步方法

    非UI线程

     1 using System;
     2 using System.Threading;
     3 using System.Threading.Tasks;
     4 
     5 namespace _00_测试
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
    12             Task<int> task = Test();
    13             Console.WriteLine($"结果为:{task.Result}");
    14             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
    15             Console.ReadKey();
    16         }
    17         private async static Task<int> Test()
    18         {
    19             int Value = 0;
    20             Task task1 = Task.Factory.StartNew(() =>
    21             {
    22                 Value++;
    23                 Thread.Sleep(100);
    24             });
    25             await task1;
    26             return Value;
    27         }
    28     }
    29 }

     执行Test()异步方法,然后获取异步方法的返回值,执行异步方法的线程会一直阻塞,直到等到要获取的返回值。但是,在UI线程中,执行异步方案的是主线程,直接就死锁了。

    UI线程

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading;
     9 using System.Threading.Tasks;
    10 using System.Windows.Forms;
    11 
    12 namespace _009__数据库
    13 {
    14     public partial class Form1 : Form
    15     {
    16         public Form1()
    17         {
    18             InitializeComponent();
    19         }
    20 
    21         private  void button1_Click(object sender, EventArgs e)
    22         {
    23             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
    24             Task<int> task = Test();
    25             Console.WriteLine($"结果为:{task.Result}");
    26             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
    27             Console.ReadKey();
    28         }
    29         private async static Task<int> Test()
    30         {
    31             int Value = 0;
    32             Task task1 = Task.Factory.StartNew(() =>
    33             {
    34                 Value++;
    35                 Thread.Sleep(100);
    36             });
    37             await task1;
    38             return Value;
    39         }
    40     }
    41 }

    在winform中,点击按钮,界面直接卡死了!!!

    分析, 执行Test()异步方法,然后获取异步方法的返回值,但是在UI线程中,await后面的操作是UI线程执行的。那么,首先异步方法执行了await中的异步任务,UI线程已经开始等这个执行结果了,UI线程阻塞等待中;而await后面的

    return Value;这一行,需要UI线程执行啊,此时UI线程阻塞等结果呢无法执行其他操作,就这么UI等返回值,子线程等UI线程等UI线程来执行  return Value;这行代码。谁也不让谁的等待下去,这就是死锁了。
  • 相关阅读:
    B站开源播放框架ijkplayer(iOS版)使用教程
    GitHub前50名的Objective-C动画相关库
    iOS系统自带的 UIAlertView 自动旋转的实现
    iOSAPP启动时实现加载广告
    每周分享第5期(2019.5.4)
    如何为Redis中list中的项设置过期时间
    对scrapy进行单元测试 -- 使用betamax
    【AMAD】betamax -- 一个ruby-VCR的模仿品,只支持requests
    【AMAD】stackprint -- 为Python加入利于调试的traceback信息
    【AMAD】Pysnooper -- 别再用print进行debug了
  • 原文地址:https://www.cnblogs.com/dfcq/p/16388646.html
Copyright © 2020-2023  润新知