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

公布结果:

相关推荐
肥硕之虎5 分钟前
渗透高级课个人学习分享
学习
2601_949720269 分钟前
flutter_for_openharmony手语学习app实战+学习进度实现
javascript·学习·flutter
Hammer_Hans9 分钟前
DFT笔记24
笔记
铁手飞鹰24 分钟前
[Linux笔记]内核裁剪
linux·笔记·linux内核裁剪
楼田莉子26 分钟前
Linux进程间通信——System V系列
linux·服务器·c++·学习·信息与通信
321.。28 分钟前
从 0 到 1 实现 Linux 下的线程安全阻塞队列:基于 RAII 与条件变量
linux·开发语言·c++·学习·中间件
啵啵鱼爱吃小猫咪35 分钟前
机器人标准DH(SDH)与改进DH(MDH)
开发语言·人工智能·python·学习·算法·机器人
时光慢煮1 小时前
从进度可视化出发:基于 Flutter × OpenHarmony 的驾照学习助手实践
学习·flutter·华为·开源·openharmony
week_泽1 小时前
GBDT 算法中构建第一个弱学习器(CART 回归树)-计算示例
学习·算法·回归·gbdt
QZ_orz_freedom1 小时前
后端学习笔记-ApaChe POI
笔记·学习