分享好友 最新动态首页 最新动态分类 切换频道
c#: 异步代码是如何解决高并发问题的?async/await、Task、IOCP/epoll
2024-12-27 02:18

环境

  • window 10
  • centos 8.2
  • .netframework
  • .netcore

参考
《MSDN:异步编程模型 (APM)》
《MSDN:异步编程模式》
《MSDN:I/o 完成端口》
《Linux下的I/O复用与epoll详解》
《浅谈async、await关键字 => 深谈async、await关键字》
《重新认识 async/await 语法糖》

和同步相反,指在处理任务时可以不用等待任务结果而继续向后执行,这样就能减少等待耗费的时间,从而达到高效利用服务器资源的效果。

异步的目的:合理规划任务的执行顺序,避免不必要的任务等待,减少服务器资源消耗,从而在服务器性能以及用户的交互体验上达到满意的效果。

多线程和异步的区别
多线程是异步的主要实现方式,事实上几乎所有的异步都有多线程的影子。但异步是从任务执行效果的角度看的,而多线程是现代计算机的一个基础功能。

同步的问题根源:阻塞当前线程、占用CPU和内存资源。

  • 多个代码块的串行:将代码块并行

     
  • winform界面的按钮事件:耗时代码采用异步调用

     

如果传统web服务器对网卡的读写采用同步调用的话,在高并发下很容易卡死,同样,如果我们程序中同步读写数据库,在高并发下也很容易卡死。

linux中的epoll(事件-响应)模型就是为了解决这种问题出现的。在window中叫做IOCP(I/O Completion Ports,也叫作完成端口)。

下面用一个场景类比epoll和IOCP的处理模型(epoll和IOCP在原理上是相同的)。

场景是这样的

有一个小镇,里面的人们要去镇外采购食物(表示:客户端向服务器发起请求,需要经过一条不宽的河流(表示:服务器的CPU、内存等资源有限,河流的管理者负责组织船只运输往返的人们(表示:CPU在时间切片内调度线程,每一个船只表示一个线程)。

改革后的方案也称之为epoll模型(linux,当然在window中叫做IOCP。

通过上面的故事,我们知道了epoll的机制,显然它是高并发下最有效的请求响应模型。
然而,当epoll出现之前,linux为了解决高并发问题还制定了select和poll模型,不过它们两个都有着很明显的缺点,可以认为它们是残次品吧。
但是,在并发程度不高的情况下,select和poll的性能和epoll也不相上下,所以nginx也是支持select和poll的)。

IOCP的原理和epoll一致。不过仍有些不同

在.net framewok时代,线程池中的线程被分为两类,和。两者的区别是 “完成端口线程专门为I/O设备读写完成后回调使用的。”

对于为什么要把线程人为的划分为两类,我还没找到准确的答案,大概是当时的设计者担心线程池内的线程被用光而导致没有线程用于回调,进而导致无限等待了吧。。。

在.net core时代,设计者有意弱化IOCP的概念,即:不想再区分和了。所以在.net framework中的I/O回调代码中,我们能明显看到可用数量的减少,但是在.net core中同样的I/O回调代码下,我们仅能观察到的可用数量减少,而的可用数量始终保持不变。

另外,当我们代码中强制调用线程池中的时(.net core,window下能观察到的可用数量减少,但是在linux下抛出异常,测试代码如下

 
 

centos下运行报错

 

那么,IOCP的概念究竟应不应该去掉呢?有没有发挥到它的作用呢
我认为:IOCP可以去掉,发挥的作用有限。

试想一下,I/O设备回调用的是,如果回调中再发起I/O读写,那么回调就又使用,这样下去,我们只要发起一次回调,之后的代码都将运行在上了。。。
听起来很恐怖的样子,不过我没有试验,不知道真正效果如何。

另外,epoll中也没有专门给I/O回调配置线程不也运行的挺好的嘛。

实际上,我认为,只要代码中涉及到I/O读写的代码调用处都使用异步的话应对高并发就没有问题了。不用再去区分什么和了,反正代码运行的都很快,但凡慢一点的都交给I/O回调了,不用担心I/O回调时没有线程可用。

异步的作用是将串行的代码改成并行的,当代码并行后,当前线程是释放回线程池还是阻塞以等待异步执行完毕,可以将异步作用分为两个

  • 异步后,当前线程不发生阻塞,释放回线程池,这适合高并发编程
  • 异步后,当前线程需要等待异步执行完毕,在并发不高的情况下,这没什么问题
  • 在.net 1.0的时候提出了

    以IAsyncResult接口为核心,支持异步的接口命名规则为: BeginXXXX、EndXXXX

  • 在net 2.0的时候提出了

    支持异步的方法以XXXXAsync命名,外加XXXXCompleted事件

  • 在.net 4.0的时候提出了

    是我们现在常用的task模式,await/async task

1. 异步编程模型(APM)

当我们调用BeginXXXX异步调用时,虽然没有立刻返回结果,但是给了我们一个信物(就是,凭借这个信物,我们可以轮训是否异步完成,或者直接阻塞当前线程以等待异步结束)。

下面是模拟的APM模式代码

 
 

2. 基于事件实现的异步编程(EAP)

根据上面介绍,使用APM方式已经可以实现异步编程了,但是使用起来比较麻烦,因为要想不阻塞当前线程就必须利用回调,而回调后会发生线程切换,这对Winform线程来说是致命的(默认,winform中只允许UI线程访问控件)。
所以,基于事件的异步编程应运而生,它不仅简化了异步代码的编写还能让回调代码运行在主线程中。
典型的组件示例是,新建一个winform工程,在窗体上拖拽一个Lable标签、一个PictureBox控件、一个Button按钮,代码如下

 
 

除了PictureBox控件,最能代表EAP模型的还有组件,它的示例MSDN上已经有详细的介绍,请参照:《MSDN:BackgroundWorker 类》

3. 基于任务实现的异步编程(TAP)

虽然有了APM和EPM两种异步模型,但在高并发时编写代码还是有难度

  • 像APM一样多层嵌套回调会形成回调地狱,不好看也不易阅读
  • EPM的事件触发调用并不适合高并发场景

从上面的分析中,我们知道:具有async/await修饰的Task代码块会被自动切割,这里就来看一下它是怎么被切割的。

以下面代码示例

 
 

为了能更好的阅读,我们将代码拷贝到VS中,剔除掉代码中的<>符号并修复掉其他报错信息,最终如下

 

这里可以自行调试运行一下,观察下运行的顺序就明白了vs是怎么将切分的代码块按顺序运行的。
主要逻辑如下

  • 第一步:创建状态机,继承IAsyncStateMachine,设置其状态为-1
  • 第二步:执行状态机的MoveNext()方法,因为状态为-1,所以执行了切割的第一块代码,并使用Task开启了第二块代码的调用
  • 第三步:第二块代码调用完成后,状态机构造器设置状态机状态为0,并调用状态机的MoveNext()方法
  • 第四步:执行状态机的MoveNext()方法,因为状态为0,所以使用Task开启了第三块代码的调用
  • 第五步:第三块代码调用完成后,状态机构造器设置状态机状态为1,并调用状态机的MoveNext()方法
  • 第六步:执行状态机的MoveNext()方法,因为状态为1,所以使用Task开启了第四块代码的调用
  • 第七步:第四块代码调用完成后,状态机构造器设置状态机状态为2,并调用状态机的MoveNext()方法
  • 第八步:执行状态机的MoveNext()方法,因为状态为2,所以直接执行了第五块代码

从分析过程可以看出,vs对async/await标记的方法生成了状态机,并按照await位置将方法中的代码块切割,最后使用状态机的回调机制按顺序执行代码,达到了最终的效果。

如果让我们自己优化上面的代码,我们会怎么生成呢
最简单的写法如下

 
 

在书写异步代码时,我们经常看到如下代码
await httpClient.GetAsync(“https://www.baidu.com”).ConfigureAwait(false);
这里的的作用是什么呢

:告诉task运行时不捕获当前的上下文。也可以简单的理解为:告诉Task调度程序,后面的代码没必要在原来的线程上运行。这就等于解放了Task调度器的手脚,Task调度时将更加迅速,因为调度器没必要等待原有线程是否空闲。

以下面代码分别在.net core3.1和.net framework平台下运行的效果说明其差别

 
 
 

关于的更多解释:《理解C#中的ExecutionContext vs SynchronizationContext》

最新文章
航海王壮志雄心克洛怎么样 航海王壮志雄心克洛详细介绍
在该游戏中,玩家可去解锁许多不同的角色,并且在技能定位以及玩法上也是十分出色,因此吸引了许多的玩家加入其中,本期小编主要是来说说航海王壮志雄心克洛,作为一个热血风格的角色,它的怒气可是能自然增长的,朋友们近期若是对于此很是
微信广告的投放逻辑,看这篇就够了!
数英用户原创文章,转载请遵守底部规范作为移动端的巨大流量入口,如何在既保证用户使用体验的同时也能带来其商业价值,一直都是腾讯,也是“微信之父”张小龙探寻的方向。众所周知,互联网的变现方式除了电商,最为普遍的就是广告流量的变
漫蛙最新最新入口在哪里?如何快速进入最新平台获取最新内容?
如果你正在寻找“漫蛙最新最新入口”,那么你来对地方了。漫蛙是一个非常受欢迎的在线平台,提供丰富的内容和服务。无论你是想了解漫蛙的最新资讯,还是需要直接访问其最新入口,这篇文章将为你提供详细的指导,帮助你快速找到正确的入口。
教你360浏览器禁用/启用地址栏复制粘贴助手图文教程
360浏览器如何禁用、启用地址栏复制粘贴助手呢?相信使用360浏览的用户在复制网站网址的时候只需使用鼠标就可以完成操作,无需使用键盘、鼠标进行操作,点击网站网址后就会出现复制网址的提示,点击即可复制。但是不少用户不喜欢这样的网址
阿里巴巴关键词源代码查看(关键词搜索代码)
本文目录一览:1、阿里巴巴国际站怎么看到别人的关键词2、数字营销阿里巴巴怎么查询有排行的关键词3、阿里巴巴诚信通会员 发布产品时的源代码编辑是什么4、阿里巴巴怎么看同行设置的关键词5、如何查看某产品关键词在阿里巴巴中文站的搜索量
超值推荐!2024年二季度南沙人气楼盘榜单,揭晓备受追捧的热门楼盘!
热度排名楼盘名地址价格1绿城·蓝湾半岛广州·南沙·深中通道旁16000元/平方米2中交·蓝色海湾港前大道南沙客运港正对面待定3越秀·珠实 | 天悦海湾南沙湾港前大道(邮轮母港南侧)24000元/平方米4保利半岛滨水大道左侧35000元/平方米5湾区
谷歌SEO优化,如何做好local business?
在当今数字化时代,谷歌搜索引擎已成为连接消费者与本地商家的重要桥梁。作为一名在SEO领域摸爬滚打多年的从业者,我深知在谷歌搜索结果中获得良好排名对于本地企业来说至关重要。这不仅意味着更多的曝光机会,还能直接转化为销售额的提升
外链建设计划:利用微信 Bug 提升网站权重
在竞争激烈的数字环境中,网站外链建设对于提高搜索引擎排名和网站可见度至关重要。利用微信 Bug 外链方法,我们可以有效地获得高质量外链,从而提升网站权重。本文将提供一个详细的外链建设规划计划和执行方案,帮助您有效地利用此策略。
除了您在Google搜索中看到的文字广告之外,展示广告网络中的网站还可以展示其他具有视觉吸引力的广告类型:文字广告 图片广告——包含照片或插图的广告富媒体广告—&m
上海天擎结合Google领先的搜索广告优化经验,为广告主定制出一套适合Google推广的解决方案MADA服务模式,通过市场分析策略、广告管理策略、数据分析策略、账户优化策略及服务保障策略全方位、专业、高效的满足企业Google推广的需求,真正
相关文章
推荐文章
发表评论
0评