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

公布结果:

相关推荐
武文斌775 小时前
arm启动代码总结
arm开发·嵌入式硬件·学习
我怕是好6 小时前
学习stm32 蓝牙
stm32·嵌入式硬件·学习
索迪迈科技6 小时前
STM32F103C8T6开发板入门学习——点亮LED灯2
stm32·嵌入式硬件·学习
摇滚侠6 小时前
Vue3入门到实战,最新版vue3+TypeScript前端开发教程,笔记03
javascript·笔记·typescript
Learn Beyond Limits7 小时前
The learning process of Decision Tree Model|决策树模型学习过程
人工智能·深度学习·神经网络·学习·决策树·机器学习·ai
岑梓铭7 小时前
考研408《计算机组成原理》复习笔记,第六章(1)——总线概念
笔记·考研·408·计算机组成原理·计组
Suckerbin7 小时前
digitalworld.local: TORMENT
笔记·安全·web安全·网络安全
凯尔萨厮8 小时前
Java学习笔记三(封装)
java·笔记·学习
YoungUpUp8 小时前
【文件快速搜索神器Everything】实用工具强推——文件快速搜索神器Everything详细图文下载安装教程 办公学习必备软件
学习·everything·文件搜索·实用办公软件·everything 工具·文件快速搜索·搜索神器
RaLi和夕8 小时前
单片机学习笔记.C51存储器类型含义及用法
笔记·单片机·学习