[.NET开发] 浅说C#异步和同步
提到异步,那么与之对应的是什么呢?同步。那么C#的异步和同步是如何工作的呢?
首先,我们先来看看栗子:
新建一个控制台应用程序,在Program文件中添加如下代码:
1 static void Main(string[] args)
2 {
3 //计时器
4 Stopwatch watch = new Stopwatch();
5 //开始计时
6 watch.Start();
7 Console.WriteLine($"{DateTime.Now.ToString()} 进入Main方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
8 //调用任务一(同步)
9 TaskOne();
10 // 调用任务二
11 TaskTwo();
12 //停止计时
13 watch.Stop();
14 Console.WriteLine($"{DateTime.Now.ToString()} 退出Main方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
15 Console.WriteLine($"主线程总耗时:{watch.ElapsedMilliseconds}ms");
16 Console.ReadKey();
17 }
18
19 ///
20 /// 任务一
21 ///
22 static void TaskOne()
23 {
24 Console.WriteLine($"{DateTime.Now.ToString()} 进入TaskOne方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
25 for (int i = 0; i < 5; i++)
26 {
27 Console.WriteLine($"{DateTime.Now.ToString()} TaskOne正在执行,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
28 System.Threading.Thread.Sleep(1000);
29 }
30 Console.WriteLine($"{DateTime.Now.ToString()} 退出TaskOne方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
31 }
32 ///
33 /// 任务二
34 ///
35 static void TaskTwo(){
36 Console.WriteLine($"{DateTime.Now.ToString()} 进入TaskTwo方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
37 for (int i = 0; i < 2; i++)
38 {
39 Console.WriteLine($"{DateTime.Now.ToString()} TaskTwo正在执行,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
40 System.Threading.Thread.Sleep(1000);
41 }
42 Console.WriteLine($"{DateTime.Now.ToString()} 退出TaskTwo方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
43 }
复制代码
这个栗子很简单,定义了两个方法:TaskOne,TaskTwo。在里面每隔一秒输出一次当前时间,和当前线程。TaskOne循环5次和TaskOne2次。然后在MAIN函数里面顺序调用,并记录MAIN函数执行的总耗时时间。
从图中可以看出,程序顺序执行TaskOne之后,再执行TaskTwo。执行线程未改变。
下面我们改改代码,用异步方式改写下TaskOne。提到异步,大家脑海里随之浮现的我想会是它吧。关键字async。当然与之成对出现的await也不能少了。先看看改写后的代码:
///
/// 任务一(异步)
///
///
static async Task TaskOneAsync()
{
Console.WriteLine($"{DateTime.Now.ToString()} 进入TaskOneAsync方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
var t = Task.Run(() =>
{
var total = 0;
for (int i = 0; i < 5; i++)
{
total++;
Console.WriteLine($"{DateTime.Now.ToString()} TaskOneAsync正在执行,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
System.Threading.Thread.Sleep(1000);
}
return total;
});
Console.WriteLine($"{DateTime.Now.ToString()} 退出TaskOneAsync方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
return await t;
}
复制代码
main函数改为调用异步方法
static void Main(string[] args)
{
//计时器
Stopwatch watch = new Stopwatch();
//开始计时
watch.Start();
Console.WriteLine($"{DateTime.Now.ToString()} 进入Main方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
//调用任务一(同步)
//TaskOne();
//调用任务一(异步)
TaskOneAsync();
// 调用任务二
TaskTwo();
//停止计时
watch.Stop();
Console.WriteLine($"{DateTime.Now.ToString()} 退出Main方法,执行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"主线程总耗时:{watch.ElapsedMilliseconds}ms");
Console.ReadKey();
}
复制代码
我们可以看到Main函数的执行时间从7082ms变为了2404ms。时间大大的缩短了。但是,在main已经结束后,TaskOneAsync依然还在运行中....,并且TaskOneAsync的执行线程不是主线程9而是10!!
下面我们来好好梳理下程序的执行过程,
可以看到当程序进入Main方法执行,进入TaskOneAsync后,线程ID依然是9,当遇到Task执行任务创建,并运行。主线程并没有阻塞,而是单独开了一个新的线程10去执行TASK任务。主线程依然顺序执行,然后退出异步方法。进入到TaskTwo中执行完毕,最后直到Main方法结束时,由于TaskOneAsync耗时较长,线程10依然继续在执行Task。直到Task结束。其实系统,在Task任务Run的时候,已经新开了一个线程执行Task里面的任务,然后主线程继续执行TaskTwo,在TaskTwo执行这段期间,任务TaskOneAsync也在另一个线程同时j执行。可见,Task会新开一个线程执行命令,当前线程不会被阻塞,因此Main线程其实根本没有像同步方式一样执行最耗时的TaskOneAsync里面的Task,而是交给了另外一个线程执行,这就是主线程执行时间,大大缩短的原因。因此,这种处理机制,对于用户体验,是比较友好的。其实,在我们开发中,常常见到以async结尾的方法。最常见的应该是IO读取,写入,以及 http资源请求相关类库方法。因为这些都是比较耗时的,一般耗时的工作,为了不影响主线程响应,我们一般都采用异步方式进行处理。
那么,当我们主线程,需要获取Task任务返回结果时,主线程会阻塞线程等待其结果返回后,再继续执行下去。改下Main方法里面的代码,
归纳总结,异步和同步,我是这样理解的:
同步:一段代码指令,在同一线程上,被顺序执行,中间没有插队。就好比去电影院买票,有很多人(待执行的指令),但是只有一个窗口(一个线程,一般指主线程)。后面的人,只能等前面的人买了票,走了,才能前一步,他们的步调是一致。所以,称之为同步。
异步:一段代码指令,在执行的时候,其中一些指令与指令之间,被执行的时间点一样,但是操作其执行的线程不一样。两者存在一段时间的并行现象。好比电影院看到排队买票的人越来越多,经理马上又新安排了一个售票员开了一个新窗口(开新线程)售票,把原来排队的人(待执行的指令),转移了一部分到新的窗口继续排队买票。这样原来售票窗口(主线程)的作业任务以及时间,则相应减少了。
异步方式其实是一种处理机制,它有好处,也有弊端。如果我们无端的滥用,会起反作用。因为,新开线程会消耗线程资源。所以,秉承一个原则:在不影响主线程响应前提下,能不用则不用。
(编辑:雷林鹏 来源:网络)
[.NET开发] 浅说C#异步和同步的更多相关文章
- python全栈开发day31-操作系统介绍,异步、同步、阻塞、非阻塞,进程
一.网络编程内容回顾 1.arp协议 #交换机 #广播.单播 2.ip协议 3.tcp和udp协议 tcp:可靠的,面向连接的,字节流传输,长连接 三次握手:一方发送请求,另一方确认请求同时发送请求, ...
- 漫话JavaScript与异步·第三话——Generator:化异步为同步
一.Promise并非完美 我在上一话中介绍了Promise,这种模式增强了事件订阅机制,很好地解决了控制反转带来的信任问题.硬编码回调执行顺序造成的"回调金字塔"问题,无疑大大提 ...
- nodejs异步转同步
项目在微信环境开发,需要获取access_token进行授权登录和获取用户信息. 特意把这块功能拿出来封装一个自定义module module.exports = new Wechat(con.app ...
- 简单的node爬虫练手,循环中的异步转同步
简单的node爬虫练手,循环中的异步转同步 转载:https://blog.csdn.net/qq_24504525/article/details/77856989 看到网上一些基于node做的爬虫 ...
- 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步
深入理解MVC MVC无人不知,可很多程序员对MVC的概念的理解似乎有误,换言之他们一直在错用MVC,尽管即使如此软件也能被写出来,然而软件内部代码的组织方式却是不科学的,这会影响到软件的可维护性 ...
- ASP.NET sync over async(异步中同步,什么鬼?)
async/await 是我们在 ASP.NET 应用程序中,写异步代码最常用的两个关键字,使用它俩,我们不需要考虑太多背后的东西,比如异步的原理等等,如果你的 ASP.NET 应用程序是异步到底的, ...
- 入门级的按键驱动——按键驱动笔记之poll机制-异步通知-同步互斥阻塞-定时器防抖
文章对应视频的第12课,第5.6.7.8节. 在这之前还有查询方式的驱动编写,中断方式的驱动编写,这篇文章中暂时没有这些类容.但这篇文章是以这些为基础写的,前面的内容有空补上. 按键驱动——按下按键, ...
- C#中的异步和同步
同步 同步(英语:Synchronization [ˌsɪŋkrənaɪ'zeɪʃn]),指对在一个系统中所发生的事件(event)之间进行协调,在时间上出现一致性与统一化的现象.说白了就是多个任务一 ...
- C# 异步转同步
当我们的程序运行时,调用了一段异步的逻辑A,这段异步的逻辑无法转化为同步(如动画.下载进度等) 而,我们又需要等待异步逻辑A处理完成,然后再执行其它逻辑B. 那就迫切需要将异步转同步了! //参数bo ...
随机推荐
- Python zip() 处理多于两个序列的参数, 存储结对的值
zip() 可以接受多于两个的序列的参数.这时候所生成的结果元组中元素个数跟输入序列个数一样 >>> a = [1, 2, 3] >>> b = [10, 11, ...
- Python tricks(3) -- list和dict的遍历和方法
每个人在使用python的过程中都会遍历list和dict. List遍历 最常用最简单的遍历list的方法 a = ["a", "b", "c&qu ...
- Windows10 64位下安装TensorFlow谷歌人工智能系统已官方原生支持
Windows10 64位下安装TensorFlow谷歌人工智能系统已官方原生支持 GitHub - tensorflow/tensorflow: Computation using data flo ...
- Python 线程调用
简介: Python 线程可以通过主线程,调用线程来执行其他命令, 为Python提供更方便的使用. 并发线程测试 # 命令调用方式 import threading,time # 定义每个线程要运行 ...
- 微信小程序——2、配置json文件
配置文件详解 主配置文件app.json 主配置文件位于主目录中,用于进行全局配置.包括页面文件的路径.窗口表现.设置网络超时时间.设置多tab等 下面通过微信最初自带小程序来学习 { "p ...
- vs下C++内存泄露检测
本文原链接: http://www.cnblogs.com/zouzf/p/4152279.html 参考文章: http://msdn.microsoft.com/zh-cn/library/x98 ...
- bootstrap6 关于bs的使用总结
在同一行中也可以有多个过了行的 "行", 即列的"总宽度"超宽度12. 即实现堆叠display:block和水平排列float的自动控制, 在div的clas ...
- JavaScript:Object属性方法
Object的属性(firebug中没有找到) var pro={ city:"shanghai", list:[,,,,] } var Person=function(name, ...
- jquery 浏览器打印
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- 一种斐波那契博弈(Fibonacci Nim)
事实上我也不知道这算是哪个类型的博弈 是在复习$NOIP$初赛的时候看到的一个挺有趣的博弈 所以就写出来分享一下 $upd \ on \ 2018.10.12$忽然发现这个其实就是$Fibonacci ...