范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

多线程和异步有什么关联和区别?如何实现异步?

  很多很多年前,有个叫 DOS 的操作系统。
  DOS 通过一行一行命令运行程序。在同一时刻里,你只可能运行一个程序,这就是 单进程系统。
  后来出现了 Windows,用户可以在系统中打开多个程序并使用它们。这就是 多进程系统。
  线程 与 进程 的关系,就如同 进程 与 系统 的关系。一个 系统 可以存在多个 进程 ,一个 进程 也可以存在多个 线程 。
  今天的主题与 多线程 的原理关系不大,因此就不在其 原理 上进行更多的说明和解释了。什么是单线程,什么是多线程
  还得记大约五、六年前,我去 KFC 和 McDonald"s 就发现了一个有趣的区别。
  在 KFC 中,收银 与 配餐 是同一人。
  顾客在点餐后,继续站在原地等待西餐,造成了 KFC 中常常能见到长长的队伍在排队。
  在 McDonald"s ,这两件事是由两个不同的人负责的。
  顾客在点餐完成后,带着号离开点餐的队伍,直接去等待配餐叫号。点餐的队伍人数比 KFC 明显少了许多。
  对比这两种模式,你会发现KFC 的模式很容易积压一长排的顾客,让他们烦于等待而最终离开。McDonald"s 的模式不容易产生排长队的顾客,并且可以让顾客早早的进入叫号等餐环节。
  我们把 线程 视作 员工 ,把 顾客 视作 任务,于是这两个例子就可以非常形象的解释什么 单线程 ,什么是 多线程 。KFC 这种模式模式就是 单线程 , 一个任务从头至尾由一 线程 完成,在一个任务完成之前,不接受第二个任务。McDonald"s 这种模式就是 多线程 , 将一个任务拆分成不同的阶段(部分),并交给不同的 线程 分别处理。什么是同步,什么是异步
  当你明白了 KFC 和 McDonald"s 后,一切就很简单了。
  线程 是 员工,同步 / 异步 就是顾客点餐的流程了。顾客不能去一下洗手间,只能呆呆地站在那里等待配置的模式就是 同步 。顾客支付以后,利用等待配置的时间去一下洗手间,找个座位的模式就是 异步 。
  显而易见,异步 可以提供更高的效率,它可以利用 等待 的时间去完成一些事情。
  在我们的代码中,一个 顾客 一边等待配置、一边做些别的事情,就是 多线程 了。
  因此,(单/多线程) 与 (同/异)步 是密不可分的两个概念。实现异步
  在正常情况下,我们写出来的代码都是 同步 的,上一行代码没做完就肯定不会执行第二行。
  所以 如何实现同步 这个问题的答案与 如何写一段代码 是一样的。
  那么,我们自然而然的就把目光放在了 如何实现异步,这一话题上了。
  在 .Net 中,我们有几种 异步 的实现方案 :ThreadBeginInvokeTaskasync / await
  下面,我会介绍每种方案是如何实现的Thread
  首先,如上面所提到的,异步 的目标就是,先开始 某个任务,然后利用等待的时间去做点 别的事情。
  很明显,这里有两个线程一个负责 某个任务。另一个负责 别的事情,并在完成 别的事情 后开始等待 某个任务 的完成。
  利用这个思想,我们可以自己做一个异步的小例子了。// 某个任务的结果 int resultOfSomeTask = 0; Thread someTask = new Thread(new ThreadStart(() => {     Thread.Sleep(1000);     resultOfSomeTask = 100; })); someTask.Start();  DoSomething(1); // 做一些别的事情 DoSomething(2); // 做一些别的事情 DoSomething(3); // 做一些别的事情  // 每隔一会儿去看看 【某个任务】 是否完成了 while (true) {     if (someTask.ThreadState == ThreadState.Stopped)         break;     Thread.Sleep(1); }  Assert.AreEqual(100, resultOfSomeTask);
  代码说明我们利用 Thread 创建一个线程,让它去完成 某个任务,我们模拟该任务需要 1秒钟,并会产生一个 100 的结果使用 Thread.Start 开始这个任务在 someTask 执行过程中,我们做作一些 别的事情利用一个轮询查看 someTask 的状态,当完成后,我们发现已经得到了 100 这个结果。
  上面例子中 while(true) 部分,我们可以使用 Thread.Join() 方法来代替以达到同样的效果。// 某个任务的结果 int resultOfSomeTask = 0; Thread someTask = new Thread(new ThreadStart(() => {     Thread.Sleep(1000);     resultOfSomeTask = 100; })); someTask.Start();  DoSomeThine(2); // 做一些别的事情 DoSomeThine(3); // 做一些别的事情 DoSomeThine(1); // 做一些别的事情  // 产生与 while(true) 同样的效果 // 当 someTask 完成后,才会继续进行 someTask.Join();  Assert.AreEqual(100, resultOfSomeTask);
  这种异步的实现方式让开发者无法只关注在 逻辑 本身,代码中混入了大量的与线程有关的代码。
  而且最不人性化的是,Thread 要么没有参数,要么只给一个 object 类型的参数,最草稿的是,它 无法返回结果,我们必须写一些额外的代码、逻辑去要主线程中得到子线程中的结果。
  题外话
  在实际生产环境中,我们往往使用 ThreadPool 来开启线程。
  毕竟每开一个线程,系统都会产生一相应的消耗来支持它。
  ThreadPool 可以开启有限个的线程,并对任务排队,仅当有线程空闲时,才会继续处理任务。BeginInvoke
  BeginInvoke 是 Delegate 上的一个成员,它与 EndInvoke 一起使用可以实现异步操作。BeginInvoke 相当于上面例子中 Thread.Start() 的功能EndInvoke 相当于上面例子中 Thread.Join() 的功能
  因为 BeginInvoke 是 Delegate 上的成员,所以我们先声明一个 Delegate///  /// 这是一个描述了一个使用整形并返回整形的委托类型。 /// 你可以使用直接使用 Func 来作为委托的类型。 ///  ///  ///  public delegate int TaskGetIntByInt(int i);
  BeginInvoke 的入参比较特别,它分为两个分部。前面的几个参数,就是委托中定义的参数后面两个参数,一个是异步任务完成时的回调,一个是可以向回调函数传入的额外参数,你可以传递任何你需要的内容至回调里,而避免了在进程内访问进程外成员的情况
  下面是一个 BeginInvoke 的例子// 这是一个耗时1秒的任务,会返回入参的平方数 TaskGetIntByInt someTask = new TaskGetIntByInt(i => {     Thread.Sleep(1000);     return i * i; });  // 定义一个函数,用于 someTask 完成时的回调 AsyncCallback callback = new AsyncCallback(ar => {     string state = ar.AsyncState as string;     Assert.AreEqual("Hello", state); });  // 开始平方数运算的任务 // callback, "HelloWorld" 根据需求传入,你也可以传 null IAsyncResult ar = someTask.BeginInvoke(10, callback, "HelloWorld");  // 开始一些别的任务 DoSomeThing(1); DoSomeThing(2); DoSomeThing(3);  // 等待 someTask 的运算结果,形如 Thread.Join() int result = someTask.EndInvoke(ar);  Assert.AreEqual(100, result);
  代码说明
  首先 创建委托的实例,你可以使用其它类型上的成员来构造,也可以像示例中那样直接写一个内部方法。
  接下来 使用 BeginInvoke 开始异步调用。 注意 这里返回了一个 IAsyncResult 类型。
  你可以把这个 IAsyncResult 理解为你在 McDonald"s 点好餐后的 号 , 每个人的 号 都是不同的,每个顾客都可以用这个 号 领取你的美食。
  在代码中,每次调用 BeginInvoke 都会产生不同的 IAsyncResult,你可以用不同的 IAsyncResult 去获取它们对应的结果。
  BeginInvoke 的时候,你还可以指定一个 回调函数 ,还可以指定一个变量,供 回调函数 使用。
  此时,someTask 已经在子线程中运行了。同时,主线程继续执行了 3 个 DoSomething() 方法。
  当你需要 someTask 的运行结果时,你只需要调用 someTask.EndInvoke(IAsyncResult) 。当子线程已经完成后,调用 EndInvoke 你可以立即得到结果。当子线程尚未完成时,调用 EndInvoke 会一直等待,等到子线程执行完成后,才可以得到结果。
  题外话
  若你的异步任务是一个耗时极长的任务,在主线程使用 EndInvoke 会 傻等 很久。
  此时,你可以将 EndInvoke 方法在 Callback 内执行。
  将 someTask 作为 回调函数 的参数传入,就可以在 Callback 内使用 EndInvoke 得到结果。TaskGetIntByInt someTask = new TaskGetIntByInt(i => {     Thread.Sleep(3000);     return i * i; });  DoSomeThing(1); DoSomeThing(2); DoSomeThing(3);  AsyncCallback callback = new AsyncCallback(_ar => {     // BeginInvoke 的最后一位参数可以通过 AsyncState 取得     TaskGetIntByInt task = (TaskGetIntByInt)_ar.AsyncState;     int result = task.EndInvoke(_ar);     Assert.AreEqual(100, result); });  IAsyncResult ar = someTask.BeginInvoke(10, callback, someTask);
  对于一个 异步 任务的结果,我们往往有两种方法处理 :在主线程中等待结果在子线程中处理结果
  对于一个耗时较短的任务,我们可以先利用 异步 将该任务放在子线程中执行。再继续在主线程中处理其它任务,最后等待 异步 任务的完成。这种方式就是 在主线程中等待结果 。
  对于一个耗时较长的任务,如果在主线程中 等待 会有可能对终端用户带来不好的应用体验。
  因此,我们不会在主线程中等待 异步 的完成。
  我们在 异步 任务开启后,就可以早早通知用户 你的任务正在处理中。同时在子线程中,当任务完成后,你可以利用数据库等手段,将 正在处理中的任务 标为 已完成,并通知他们。Task
  从 .Net4.0 开始,Task 成为了实现 异步 的主要利器。
  Task 的用法与 JavaScript 中的 Promise 非常接近。
  Task 表示一个 异步 任务。废话不多说,我们先写一个返回 Task 的方法。// Task 表示这是一个返回 int 类型的 Task private Task AsyncPower(int i) {     // 返回一个任务     // 使用 Task.Run 相当于先创建了一个 Task     // 再 Start     return Task.Run(() =>     {           // 该任务会耗时 1 秒钟         Thread.Sleep(1000);         // 1 秒钟后会返回参数的平方         return i * i;     }); }
  与之前提到的相同,我们有两种方法处理这个 Task 的结果 :在主线程中等待结果在子线程中处理结果
  我们看看两种模式分别是如何实现的在主线程中等待结果
  直接访问 Task.Result 属性,就可以等待并得到 异步 任务的结果。var task = AsyncPower(10);  // 这里会等 1 秒 int result = task.Result;   // result = 100
  怎么样 ? 是不是超级简单 ?在子线程中处理结果
  使用方法 ContinueWith 可以添加一个方法,在 Task 完成后被执行。
  这个 ContinueWith 和 JavaScript 里的 Promise 的 then 方法有着异曲同工的效果。var task = AsyncPower(10);  task.ContinueWith(t =>  {     int result = t.Result;     // result = 100 });
  怎么样 ? 是不是依然超级简单 ?
  就像之前说的,Task 用起来就像 Promise,Promise 最大的特点就是可以用一步一步 then 下去。$.get("someurl")     .then(rlt => foo(rlt))     .then(rlt => bar(rlt));
  Task 的 ContinueWith 也支持这样的编写方法 :var task = AsyncPowe(10); task.ContinueWith(t =>  {     // some code here }).ContinueWith(t =>  {     // some code here }).CondinueWith(t => {     // some code here }); async / await
  这个 .Net 4.5 加入的关键字,让 异步代码 写起来和 同步代码 没什么区别了。
  我们先看看下面的同步代码int Power(int i) {     return i * i; }  void Main() {     int result = Power(10);     Console.WriteLine(result); // 100     Console.ReadLine(); }
  把上面的代码改成异步代码,只需要几个小小的改动 :将 Power 的返回值改为 Task修改返回结果,使用 Task.Run 包装返回的结果为调用 Power 的代码前加上 await 关键字为有 await 关键字的方法加上 async 关键字
  新的代码如下Task Power(int i) {     return Task.Run(()=>     {         Thread.Sleep(100); // 模拟耗时         return i * i;     }); }  async void Main() {     Console.WriteLine("Hello");     int result = await Power(10);     Console.WriteLine(result); // 100     Console.ReadLine(); }
  运行一下,发现没什么区别。
  如果你向控制台输出线程ID的话,你会发现 Console.WriteLine("Hello") 和 Console.WriteLine(result) 并不工作在同一个线程同。
  为什么会有这样的效果 ?
  因为 编译器,你会发现,和之前的异步实现不同,async 和 await 不是某个封装了复杂逻辑的类型,而是两个关键字。
  关键字的意义就是编译过程。
  在编译时,遇到 async 就会知道这是一个存在着异步的方法,编译器向这个类型添加一些额外的成员来支持 await 操作。
  当遇到 await 关键字时,编译器会从当前行截断,并向后面的代码编译到 Task.ContinueWith 中去。
  这样一来,看似同步的代码,经编译后,就会一拆为二。
  前部分运行在主线程中,后部分运行在子线程中,分割点就是 await 所在的代码行。慎用异步
  几种在 .Net 平台中使用 异步 的方法都介绍完了,希望大家能够对 异步 编程有了一定的了解和认识。
  但是,在实际生产中,依赖要慎用异步。
  异步 在带来性能提高的同时,还会带来一些更复杂的问题:线程安全
  线程间的切换并不是有着类似 事务 的特征,它无法保证两个线程对同一资源的读写的完整性。
  而且大部分情况下,一个线程操作完,就会被挂机执行另一个线程,所以对于多个线程访问同一资源,需要考虑线程安全的问题。
  换句话说,就是保证一个线程在执行一个最小操作时,另一个线程不允许操作该对象。调试难
  异步 的本质就是 多线程 ,当你尝试用断点调试代码时,由于两个线程都在你的代码中运行,因此常常出现从这个线程的断点进入另一个线程的断点的情景。
  需要依赖 IDE 中更多的工具和设置,才能解决上述的问题。不统一的上下文
  异步 代码往往在子线程中运行。
  子线程 很可能会使用在 主线程 中已经施放的资源。
  比如using(var conn = new SqlConnection("........")) {     conn.Open();      // 假定一个根据用户名查询用户ID的方法     Tast task = UserService.AsyncGetUserId(conn, "Admin");      task.ContinueWith(t =>      {         // 此时的 conn 已经被主线程释放了         UserService.DoSomethingWithConn(conn);     }); }
  你需要使用一些额外的代码来解决这些问题。并且这些代码不一定具备通用性,往往要具体问题具体分析。
  因此在实际任务中,到底选择 同步 还是 异步 要视具体情况而定。
  今天本文介绍了几种实现 异步 的方法,不能说它们之间谁比谁更好一点,各有优劣。
  篇幅原因,将不再对几种方案进行对比,会在以后的文章中详细地介绍各自优劣。

全系标配手机车钥匙,秦Pro超越版520上线5月20日,比亚迪秦Pro超越版正式上市。整车外观动感时尚,配置实用超前,还搭配了堪称黑科技的手机NFC车钥匙,官方价位仅为7。98万9。98万。值得一提的是,在6月30日前订车可哈弗F7销量再度破万累计销量突破18万4月,哈弗F7终端销售10,911辆,环比增长80,成为当月最热潮品SUV。迄今,哈弗F7累计销量已突破18万辆,并带动哈弗F系成为细分市场最具吸引力的SUV车型。疫情期间,哈弗F新一代智跑品质制胜起亚正埋头赶上车市脉动。在竞争最为激烈的SUV市场,新一代智跑上市一年销量破10万辆月均销量保持在6000辆以上,成为东风悦达起亚旗下表现最出色的产品。其中,产品品质与产品力的持续雕琢光影声色翼联EDUP1080P智能自动对焦摄像头上市报刊杂志跌落大众视野,书信短信已然明日黄花,数字网络将21世纪彻底点亮。走过缤纷静谧的图文时代,视频开启了人们遍览山河的上帝之眼,直播又让一场时光盛宴活灵活现。随着网络大幅提速升级测试结果流出你想知道的刀片电池安全测试都在这2020年3月刀片电池以征服针刺测试而广为人知,动力电池的安全性也由此备受关注。很多消费者想要了解更多刀片电池的安全信息,除了针刺测试之外,刀片电池还接受过哪些测试?表现如何呢?我六款车型同时首发恒大汽车务实再出发01hr造车新势力最大一匹黑马,恒大汽车迈出了坚实的一步。8月3日,恒大汽车6款新车同时全球首发,在汽车圈和金融界掀起一道道飓风。造车新势力已举步维艰?恒大汽车给出了有力的答案。百新平台新实力第十代索纳塔正式上市近日,北京现代第十代索纳塔正式上市,共5款车型,售价区间为16。18万20。58万元。新车定位智慧运动美学中高级座驾。作为现代汽车新一代iGMP平台下的首款量产车型,第十代索纳塔将造车驶入快车道!恒大健康更名为恒大汽车近来,恒大健康(0708。HK)可谓动作频频,利好不断。继大幅降低投资门槛至每手500股后,7月27日再发公告,公司名称更改为恒大汽车。分析认为,此举不仅标志着其主营业务已明确为新7月新车SUV主导,轿车K5凯酷比亚迪汉EV备受关注继6月车市迎来第一波新车高峰后,7月各厂商再次集中火力推出多款新车备战成都车展。SUV是今年车市最热门的市场。据DaasAuto达示数据梳理,7月新车共计42款,其中19款全新车型年味家乡味好运总相随翼联EDUP欢度元宵佳节红红火火过大年,欢欢喜喜闹元宵。2月26日,一场别开生面的元宵欢宴在翼联EDUP热烈举办。翼联舞台张灯结彩,来自五湖四海的翼家人踊跃报名,精心准备了各自的拿手好菜,团聚在一起,分享4G无处不在为何还用4GWiFi4G无线路由器上网更简单5G小荷尖尖,4G已成标配,4GWiFi是何方神圣?宽带网络日益普及,4GLTE无处不在,为何还用4GWiFi?畅玩4GWiFi更省电上网时,耗电量主要跟手机的发射功率有关。而发射
我们到底要不要买,小洁智能扫地机告诉你,值得买智能扫地机器人的出现,给我们的生活带来了很大的便利,清扫干净还不乱跑,一定程度上解放了双手。很多人都问我,我们有必要买一台扫地机器人吗?很多人都在犹豫,我们到底要不要买,我告诉你,屏蔽链接被限期整改,互联互通必须玩真的据21世纪经济报道消息,9月9日下午,工信部有关业务部门召开了屏蔽网址链接问题行政指导会。会上,工信部提出有关即时通信软件的合规标准,要求限期内各平台必须按标准解除屏蔽,否则将依法多种接口的谷歌Coral模块,总有一款适合您大家好,我是人见人爱的小月月。今天我们继续聊聊人工智能开发板。一提到Coral这个名字,大家就会想到谷歌的各种黑科技。去年Google已经发布过一块秒天秒地的人工智能开发板,名字叫苦等RTX30系空气卡不如先准备配件,几款在用机箱电源总结点评虽然目前比特币价格已经腰斩,但众人期望的矿难并未如期而来,我们想要原价购买RTX30系显卡的愿望在短期内仍旧不会实现,RTX30系显卡对于绝大部分人来说仍旧是空气卡。对于刚需升级的2019年必买的6类开源硬件Linux开发板BeagleBone和Cubie专场大家好,我是人见人爱的小月月,在之前的文章里,我们聊到了2019年必买的6类高性价比Linux开发板OlinuXino专场还有2019年必买的6类高性价比Linux开发板BPI专场教育机器人K12时代落幕后,大厂掀起教育智能硬件大战过去,K12教育一度被视为教育领域里最长且最大的赛道。7月24日晚,当中共中央办公厅国务院办公厅印发关于进一步减轻义务教育阶段学生作业负担和校外培训负担的意见(以下简称双减文件),女性选什么车?奇瑞小蚂蚁制动好续航长,送给老婆很适合虽然说,当下的汽车市场中主要的购车群体是男性用户,但是随着当今社会女性消费者的自主意识越来越强烈,她们的购车意识也越来越强,当今的汽车市场中也出现了很多专门针对女性用户而退出的小型扫地机器人哪个牌子好干货满满科技在发展,人们生活水平逐渐上升,近两年受疫情的影响,我们也是越来越注重家里的清洁与消毒,所以,扫地机器人也逐渐走进每家每户。但仍有但是还有很多朋友不会挑选,今天就给大家带来了一满全职宝妈是如何上班带娃两兼顾?原来是我选对了扫地机作为一个全职宝妈,上班忙碌,下班劳累,根本无暇顾及家中地面卫生清洁。而此刻如果有一台智能扫地机器人来帮忙,那家居清洁都变得容易多了,我也能够更加专注的上班带娃了。不过,朋友和我说扫扫地机器人真的值得买吗?小洁智能扫地机性价比如何扫地机器人真的值得买吗?要问我的话,那就是非常值!!经常上班加班整个人都非常累,下班或者是周末时间根本不想打扫卫生。但是看着地面的灰尘毛发等垃圾,又不能不做,不然就要生活在垃圾堆里高性价比扫地机器人来了,打破扫地机市场尴尬格局扫地机器人的功能越来越强大,智能规划路径清扫,逐渐走入越来越多的家庭。但是市面上那么多的扫地机器人。我们又该如何去挑选呢?我在下面给大家整理了一下,希望能帮助到大家。顺便还附带了扫