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

公布结果:

相关推荐
weixin_5134499610 分钟前
walk_these_ways项目学习记录第八篇(通过行为多样性 (MoB) 实现地形泛化)--策略网络
开发语言·人工智能·python·学习
LX5677724 分钟前
传统编辑如何考取AI内容编辑师认证?学习路径详解
人工智能·学习
songyuc33 分钟前
BM2『链表内指定区间反转』学习笔记
学习·链表
L1624761 小时前
Kubernetes 完整学习手册(1 主多从 + 纯 YAML 部署 + 访问原理)
学习·容器·kubernetes
weixin_513449961 小时前
walk_these_ways项目学习记录第七篇(通过行为多样性 (MoB) 实现地形泛化)--核心环境下
人工智能·python·学习
管鲍考试学习系统2 小时前
在线考试系统是什么?功能、部署、应用场景全详解(管鲍考试学习系统 V8.0 深度版)
学习·架构·在线考试·考试系统·培训考试·考试练习
CheerWWW2 小时前
深入理解计算机系统——位运算、树状数组
笔记·学习·算法·计算机系统
中屹指纹浏览器2 小时前
2026浏览器指纹检测技术演进与多账号反检测实战策略
经验分享·笔记
独小乐3 小时前
012.整体框架适配SDRAM|千篇笔记实现嵌入式全栈/裸机篇
c语言·汇编·笔记·单片机·嵌入式硬件·arm·gnu