异步/IO 和并行

Posted

技术标签:

【中文标题】异步/IO 和并行【英文标题】:Async/IO and Parallelism 【发布时间】:2018-09-16 17:24:00 【问题描述】:

我正在使用aiohttp 创建一个 Async/IO 网络服务器。但是,据我了解,Async/IO 意味着服务器只能在一个处理核心上运行。另一方面,像uwsgi 这样的常规同步服务器可以通过真正的并行线程和进程充分利用计算机的计算资源。那么,如果 Async/IO 的并行性比多处理少,为什么它是新的和流行的呢?像aiohttp 这样的异步服务器可以多处理吗?

【问题讨论】:

异步编程的重点是在一个 CPU 线程中填充多个执行线程。这允许您在一个 CPU 内核上处理多个(例如数千个)I/O 请求。但是,异步代码糟糕用于并行化 CPU 密集型任务,因为无论如何一切都在一个线程中运行。 @ForceBru 我试过这样的事情:from multiprocessing import Pool; pool = Pool(4); pool.map(web.run_app, [app, app, app, app])。这在性能方面有意义吗? 好吧,如果您的服务器在一个进程中运行时无法处理太多请求,那可能是这样。否则asyncio 应该没问题。而且它也不会给你的电脑带来太多的负担。 Re: 趋势——基本上,一些“更并行”的模型可以,特别是如果实施不善(从历史上看,它们通常实施不善),比异步方法更多的开销。线程之间的切换涉及从用户空间到内核空间的上下文切换;在单个进程中在两个不同的调用堆栈上下文之间跳转比切换线程的开销要低得多。 ...通常,理想的解决方案介于两个世界之间——即。使用线程池,然后在每个线程进行轻量级应用程序级上下文切换。也就是说,关于这个话题有很多强烈的意见,而答案可能会引起争议的问题是我们试图远离这里的地方。 【参考方案1】:

那么,如果 Async/IO 的并行性不如多处理,为什么它是新潮的?

两者解决不同的问题。 Asyncio 允许编写 异步 代码而不用“回调地狱”。 await 允许使用循环、ifs、try/except 等结构,并在await 点自动切换任务。这可以为大量连接提供服务,而无需为每个连接生成一个线程,而是使用看起来的可维护代码,就好像它是为阻塞连接而编写的。因此,asyncio 主要有助于解决唯一瓶颈是等待外部事件的代码,例如网络 IO 和超时。

另一方面,多处理是关于并行执行 CPU-bound 代码,例如科学计算。由于the GIL 导致操作系统线程无济于事,因此多处理会产生分离的操作系统进程并在它们之间分配工作。这是以进程无法轻松共享数据为代价的——所有通信要么通过管道序列化,要么使用专用的proxies。

理论上,多线程异步风格的框架是可能的——例如,Rust 的tokio 就是这样——但由于 Python 的 GIL 阻止了对多核的利用,因此不太可能带来性能优势。结合 asyncio 和 multiprocessing 可以处理不依赖于共享状态的 asyncio 代码,asyncio 通过run_in_executorProcessPoolExecutor 支持。

【讨论】:

【参考方案2】:

Gunicorncan帮你:

gunicorn module:app --bind 0.0.0.0:8080 --worker-class aiohttp.GunicornWebWorker --workers 4

【讨论】:

谢谢!我不知道 Gunicorn 可以运行 aiohttp 应用程序!

以上是关于异步/IO 和并行的主要内容,如果未能解决你的问题,请参考以下文章

Python协程中的并行异步IO

gj12-1 协程和异步io

并行处理许多 API 请求与异步/等待 [关闭]

Python之并发并行阻塞非租塞同步异步IO多路复用

并发/并行/同步/异步概念

python 同步异步,并发并行,同步锁