同步是什么(已同步是什么意思啊)( 二 )


协同学和greenlets在异步开发方面最有趣的区别在于,前者需要Python语言特有的关键字和特性才能工作,而后者则不需要 。我的意思是,基于协同学的应用程序需要用特定的语法编写,而基于greenlet的应用程序看起来几乎就像普通的Python代码 。这非常酷,因为在某些情况下,它允许同步代码异步执行,这是asyncio等协同方案无法做到的 。
【同步是什么(已同步是什么意思啊)】那么greenlet中asyncio的等价库有哪些呢?我知道三个基于greenlet的异步包:Gevent、Eventlet和Meinheld,虽然最后一个更像Web服务器而不是一般的异步库 。它们都有自己的异步循环实现,并且都提供了一个有趣的“猴子打补丁”功能,替代Python标准库中的阻塞函数,比如执行网络和线程的函数,并基于greenlets实现等价的非阻塞版本 。如果您有一些想要异步运行的同步代码,这些包将会帮助您 。
据我所知,唯一明确支持greenlet的Web框架是Flask 。这个框架会自动监控,当你想在greenlet Web服务器上运行时,它会相应地自我调整,无需任何配置 。这样做,你需要注意不要调用阻塞函数,或者如果你想调用阻塞函数,你最好用猴子补丁“修复”那些阻塞函数 。
然而,Flask并不是唯一受益于greenlets的框架 。其他Web框架,比如Django和Bottle,虽然没有greenlet,但是通过组合一个greenlet Web服务器,使用monkey-patching来修复阻塞函数,也可以异步运行 。
异步比同步更快吗?对于同步和异步应用程序的性能有一个普遍的误解——异步应用程序比同步应用程序快得多 。
我需要澄清一下 。无论是同步还是异步编写,Python代码的运行速度几乎相同 。除了代码,还有两个因素会影响并发应用程序的性能:上下文切换和可伸缩性 。
上下文切换在所有正在运行的任务中公平地分担CPU所需的工作,称为上下文切换,会影响应用程序的性能 。对于同步应用程序,这项工作由操作系统完成,它基本上是一个黑盒,不需要配置或微调选项 。对于异步应用程序,上下文切换是通过循环来完成的 。
的默认循环实现是由asyncio提供的,用Python写的,效率不是很高 。uvloop包提供了一个替代的循环方案,其中部分代码用C编写,以获得更好的性能 。Gevent和Meinheld用的事件循环也是用c写的,Eventlet用的是Python写的循环 。
高度优化的异步循环在上下文切换上比操作系统效率更高,但根据我的经验,要想看到实际的效率提升,必须运行非常大的并发量 。对于大多数应用程序,我认为同步和异步上下文切换之间的性能差距并不明显 。
扩展性我认为异步更快这个神话的来源是异步应用程序通常比同步更有效地使用CPU,可以更好地扩展,并且以更灵活的方式扩展 。
想象一下,如果上图中的同步服务器同时收到100个请求,会发生什么 。该服务器一次最多只能处理四个请求,因此大多数请求将留在队列中,等待分配给它们一个工作器 。
相反,异步服务器会立即创建100个任务(或者如果使用混合模式,在四个异步工作线程中的每一个上创建25个任务) 。使用异步服务器,所有请求都将被立即处理,无需等待(尽管公平地说,这种方案中还有其他瓶颈,比如对活动数据库连接的限制) 。
如果这100个任务主要使用CPU,那么同步和异步方案的性能会差不多,因为每个CPU的速度是固定的,Python总是以相同的速度执行代码,应用要做的工作也是一样的 。但是,如果这些任务需要进行大量的I/O操作,那么同步服务器只能处理四个并发请求,无法实现CPU的高利用率 。另一方面,异步服务器将使CPU更忙碌,因为它并行运行所有这100个请求 。
你可能会想,为什么不能运行100个同步工作器,那么两台服务器就会有相同的并发性 。请注意,每个工作人员都需要自己的Python解释器和与之相关的所有资源,以及应用程序及其资源的单独副本 。您的服务器和应用程序的大小将决定您可以运行多少个worker实例,但通常这个数字不会很大 。另一方面,异步任务非常轻量级,并且在单个工作进程的上下文中运行,因此它们具有明显的优势 。
综上所述,当只有以下几种场景时,我们可以说异步可能比同步更快:
存在高负载(没有高负载,访问的高并发性就没有优势)任务是 I/O 绑定的(如果任务是 CPU 绑定的,那么超过 CPU 数目的并发并没有帮助)你查看单位时间内的平均请求处理数 。如果你查看单个请求的处理时间,你不会看到有很大差别,甚至异步可能更慢,因为异步有更多并发的任务在争夺 CPU 。结论希望这篇文章能解答异步代码的一些困惑和误解 。我希望你能记住以下两个要点:


推荐阅读