• C#中的异步多线程补充1


    1、都是同步情况下的示例

            static int CPUMission(int val)
            {
                Console.WriteLine($"CPU Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                for (long i = 0; i < 100_000_000; i++) ;
                Console.WriteLine($"CPU End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                return val;
            }
            static int IOMission(int val)
            {
                Console.WriteLine($"IO Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Thread.Sleep(3000);
                Console.WriteLine($"IO End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                return val;
            }
            static void Main(string[] args)
            {
                Console.WriteLine($"Main Thread Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                //Task<int> t1 = Task.Run(() => IOMission(3));
                int t1 = IOMission(3);
                int s1 = CPUMission(3);
                Console.WriteLine($"Main Thread End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Console.ReadLine();
            }

    输出:同步按顺序依次执行,直观,简单

    Main Thread Start:1
    IO Start:1
    IO End:1
    CPU Start:1
    CPU End:1
    Main Thread End:1

    2、启用线程池线程处理IO任务的情况

            static void Main(string[] args)
            {
                Console.WriteLine($"Main Thread Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Task<int> t1 = Task.Run(() => IOMission(3));
                //int t1 = IOMission(3);
                int s1 = CPUMission(3);
                Console.WriteLine($"Main Thread End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Console.ReadLine();
            }

    输出:

    Main Thread Start:1
    CPU Start:1
    IO Start:4
    CPU End:1
    Main Thread End:1
    IO End:4

    可以发现,因为IO任务是通过另开线程执行,所以IO任务和CPU任务之间的顺序就是不可预测的了。

    3、现在调用结果

            static void Main(string[] args)
            {
                Console.WriteLine($"Main Thread Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Task<int> t1 = Task.Run(() => IOMission(3));
                //int t1 = IOMission(3);
                int s1 = CPUMission(3);
                Console.WriteLine(t1);
                Console.WriteLine(s1);
                Console.WriteLine($"Main Thread End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Console.ReadLine();
            }

    输出:

    Main Thread Start:1
    CPU Start:1
    IO Start:4
    CPU End:1
    System.Threading.Tasks.Task`1[System.Int32]
    3
    Main Thread End:1
    IO End:4

    可以看到,虽然调用WriteLine方法打印t1,但t1的返回值是个Task<int>,并不是想要拿到的值,并且此时IO所在线程仍然不是同步的。(IO End在Main Thread End之后出现)

    4、调用Task.Result

    把Console.WriteLine(t1)修改成Console.WriteLine(t1.Result);

    输出结果如下:

    Main Thread Start:1
    CPU Start:1
    IO Start:4
    CPU End:1
    IO End:4
    3
    3
    Main Thread End:1

    可以看到取得了输出结果,并且按照同步地方式执行了后面的语句,也就是说,Task.Result会阻塞当前线程,让其等待Task.Result取得结果,但在之前,异步和同步方法执行顺序仍然是不可预测的。

    5、异步方法

    通过调用一个异步方法来调用IOMission

            static int IOMission(int val)
            {
                Console.WriteLine($"IO Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Thread.Sleep(3000);
                Console.WriteLine($"IO End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                return val;
            }
            static async Task<int> UseIOMission(int val)
            {
                int result = await Task.Run(() => IOMission(val));
                return result;
            }

    调用

            static void Main(string[] args)
            {
                Console.WriteLine($"Main Thread Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Task<int> t1 = UseIOMission(3);
                //Task<int> t1 = Task.Run(() => IOMission(3));
                //int t1 = IOMission(3);
                int s1 = CPUMission(3);
                Console.WriteLine(t1.Result);
                Console.WriteLine(s1);
                Console.WriteLine($"Main Thread End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                Console.ReadLine();
            }

    输出结果:

    Main Thread Start:1
    IO Start:4
    CPU Start:1
    CPU End:1
    IO End:4
    3
    3
    Main Thread End:1

     这样可能还看不到区别,但如果在异步方法中打印一下线程Id

            static async Task<int> UseIOMission(int val)
            {
                Console.WriteLine($"UseIO Start:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                int result = await Task.Run(() => IOMission(val));
                Console.WriteLine($"UseIO End:{Thread.CurrentThread.ManagedThreadId.ToString()}");
                return result;
            }

    Main Thread Start:1
    UseIO Start:1
    IO Start:4
    CPU Start:1
    CPU End:1
    IO End:4
    UseIO End:4
    3
    3
    Main Thread End:1

    会看到await前后线程Id会改变,也就是说,await Task.Run是异步开启,而Task.Run本身是同步地开启新线程,这一步比较细节,不一定说的正确,会在后面进一步补充修正。

    补充一个小例子:

            private void SyncExecuteLongTimeMission()
            {
                Thread.Sleep(3000);
                MessageBox.Show("Mission End");
            }
            private async void AsyncExecuteLongTimeMission()
            {
               await Task.Run(() => SyncExecuteLongTimeMission());
                MessageBox.Show("Async End");
            }
    
            private void NoAsync_Click(object sender, EventArgs e)
            {
                SyncExecuteLongTimeMission();
            }
    
            private void Async_Click(object sender, EventArgs e)
            {
                AsyncExecuteLongTimeMission();
            }
    
            private void OnlyTask_Click(object sender, EventArgs e)
            {
                Task.Run(() => SyncExecuteLongTimeMission());
                MessageBox.Show("Task.Run End");
            }

    使用winForm来查看,单纯的Task.Run任务也不会阻塞UI主线程,但会先行显示Task.Run End然后才是Mission End,但如果是在async方法中await Task.Run,那么不仅不会阻塞主线程,还会先Mission End然后才是Async End。

    也就是说,async await提供了一种以同步方式调用异步方法的方式,它不仅不会阻塞主线程,还会以同步调用的感觉来返回值,尽管它实际上是异步方法。

  • 相关阅读:
    《大话设计模式》的一些总结
    一个仿jdkd的动态代理
    一道笔试题(构造数组)
    c# 汉字转拼音
    IDEA常用插件盘点(香~~)
    服务器概念、应用服务器盘点大科普
    创建一个简单的Struts 2程序
    JAVA(Object类、Date类、Dateformat类、Calendar类)
    DQL查询语句和约束
    MySQL操作语句
  • 原文地址:https://www.cnblogs.com/NicolasLiaoran/p/13132029.html
Copyright © 2020-2023  润新知