C# .Net学习笔记—— 异步和多线程(await/async)

一、介绍

1、控制台测试await/async

2、C# 5.0 .Net framework4.5 CLR4.0 以后才有,本身是一种语法糖

二、基本测试

1、不加await测试。

cs 复制代码
        private async static Task TestAsync() 
        {
            Log.Info($"当前主线程id={Thread.CurrentThread.ManagedThreadId}");
            NoReturnNoAwait();
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(300);
                Log.Info($"Main Thread Task ManagedThreadID = {Thread.CurrentThread.ManagedThreadId}");
            }
        }
       

     private static async void NoReturnNoAwait() 
        {
            Log.Info($"NoReturn Sleep before await,ThreadID={Thread.CurrentThread.ManagedThreadId}");
            TaskFactory taskFactory = new TaskFactory();
            Task task = taskFactory.StartNew(() =>
            {
                Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(3000);
                Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");
            });
            Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");
        }

2、加await测试。

cs 复制代码
        private async static Task TestAsync() 
        {
            Log.Info($"当前主线程id={Thread.CurrentThread.ManagedThreadId}");
            NoReturn();
            //NoReturnNoAwait();
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(300);
                Log.Info($"Main Thread Task ManagedThreadID = {Thread.CurrentThread.ManagedThreadId}");
            }
        }

        private static async void NoReturn() 
        {
            Log.Info($"NoReturn Sleep before await,ThreadID={Thread.CurrentThread.ManagedThreadId}");
            TaskFactory taskFactory = new TaskFactory();
            Task task = taskFactory.StartNew(() => 
            {
                Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(3000);
                Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");
            });
            await task;  //主线程到这里就返回了,执行主线程任务
            Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");
        }

结果: 从打印出来的两种执行顺序来看,加了await以后,主线程运行到await这行就会执行

回主线程任务。而await后面的代码将由主线程或其他线程来执行

**原理:**await后面的代码,会被封装成委托,在await task之后成为回调(编译器功能,状态机实现) ,这个回调的线程是不确定的,可能是主线程,可能是子线程也可能是其他线程。

它可以等价于task.ContinueWith(t=>{}) 这里包起来

验证一下:

cs 复制代码
       private async void AwaitTest() 
        {
            //方法一:
            NoReturn();
            //方法二:
            TaskFactory taskFactory = new TaskFactory();
            Task task = taskFactory.StartNew(() =>
            {
                Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(3000);
                Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");
            });
            task.ContinueWith(t =>
            {
                callBack();
            });
            await task;
        }
        private static async void NoReturnNoAwait()
        {
            Log.Info($"NoReturn Sleep before await,ThreadID={Thread.CurrentThread.ManagedThreadId}");
            TaskFactory taskFactory = new TaskFactory();
            Task task = taskFactory.StartNew(() =>
            {
                Log.Info($"NoReturn Sleep before,ThreadID={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(3000);
                Log.Info($"NoReturn Sleep after,ThreadID={Thread.CurrentThread.ManagedThreadId}");
            });
            Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");
        }
        private void callBack()
        {
            Log.Info($"我是一个回调。。");
            Log.Info($"NoReturn Sleep after await,ThreadID={Thread.CurrentThread.ManagedThreadId}");
        }

三、返回值问题

1、不需要传值的时候,我们返回值就写成Task或者void都可以

2、需要传值的话 ,可以使用这种带泛型传值

四、小案例

cs 复制代码
       private void MainThread() 
        {
            Log.Info("主线程Start");
            Async();
            Log.Info($"aaa {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
        }

        private async void Async()
        {
            Log.Info($"ddd {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            await Task.Run(() =>
            {
                Thread.Sleep(500);
                Log.Info($"bbb {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            });
            Log.Info($"ccc {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
        }

猜测执行顺序:

1、打印主线程Start

2、主线程进入Async方法,打印ddd

3、碰到了await,主线程返回回去执行,打印aaa

4、子线程等待500毫秒后,并行打印bbb

5、最后回调打印ccc

公布结果:

相关推荐
克里斯蒂亚诺更新3 小时前
ruoyi角色权限的对应关系
笔记
a1117765 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao5 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
破碎的南瓜7 小时前
sqli--sql注入过关笔记(1,2,3,4,5,9)
数据库·笔记·sql
你想知道什么?7 小时前
线性回归-学习笔记
笔记·学习·线性回归
鱼毓屿御7 小时前
从「只会聊」到「边想边做」的跃迁
前端·学习·react.js
谙弆悕博士7 小时前
系统集成项目管理工程师教程(第3版)笔记——第17章:法律法规和标准规范
笔记·职场和发展·学习方法·业界资讯·软考·法律·法规
AOwhisky9 小时前
Python 学习笔记(第十五期)——运维自动化(下·后篇):堡垒机实战——paramiko高阶篇
运维·python·学习·云原生·自动化·运维开发
谙弆悕博士9 小时前
系统集成项目管理工程师教程(第3版)笔记——第4章:信息系统架构
笔记·系统架构·项目管理·创业创新·学习方法·业界资讯·物理
minglie110 小时前
zynq中linux系统的自动登录和免密登录
学习