【发布时间】:2013-04-12 10:38:47
【问题描述】:
我最近一直在使用烧瓶在 python 中进行一个宠物项目。它是一个简单的 pastebin,带有 pygments 的服务器端语法高亮支持。因为这是一项代价高昂的任务,所以我将语法突出显示委托给 celery 任务队列,并在请求处理程序中等待它完成。不用说,这只不过是减轻了另一个工作人员的 CPU 使用率,因为等待结果仍然会锁定与 Web 服务器的连接。 尽管我的直觉告诉我要避免像瘟疫一样过早的优化,但我还是忍不住研究了异步。
异步
如果最近一直在关注 python web 开发,你肯定已经看到异步无处不在。 async 所做的是带回协作多任务,这意味着每个“线程”决定何时何地让步给另一个。这种非抢占式进程比操作系统线程更有效,但仍然有它的缺点。目前似乎有两种主要方法:
- 事件/回调风格的多任务处理
- 协程
第一个通过在事件循环中执行的松散耦合组件提供并发性。尽管这在竞争条件方面更安全并提供了更高的一致性,但与抢先式多任务处理相比,它的直观性和编码难度要小得多。
另一种是更传统的解决方案,更接近线程编程风格,程序员只需手动切换上下文。虽然更容易出现竞争条件和死锁,但它提供了一个简单的解决方案。
目前大多数异步工作都是在所谓的 IO-bound 任务上完成的,这些任务会阻塞以等待输入或输出。这通常是通过使用可以调用的轮询和基于超时的函数来完成的,如果它们返回负数,则可以切换上下文。
尽管有这个名字,这也可以应用于CPU-bound任务,可以委托给另一个工作人员(线程、进程等),然后非阻塞地等待屈服。理想情况下,这些任务将以异步友好的方式编写,但实际上这意味着将代码分成足够小的块以防止阻塞,最好不要在每一行代码之后分散上下文切换。这对于现有的同步库来说尤其不方便。
由于方便,我决定使用 gevent 进行异步工作,并想知道如何在异步环境中处理 CPU 密集型任务(使用期货、芹菜等?)。
如何在flask等传统Web框架中使用异步执行模型(本例中为gevent)? python(futures、task queues)中这些问题有哪些普遍认可的解决方案?
编辑:更具体地说 - 如何将 gevent 与烧瓶一起使用以及如何在这种情况下处理 CPU 密集型任务?
EDIT2:考虑到 Python 的 GIL 会阻止线程代码的最佳执行,这仅留下多处理选项,至少在我的情况下如此。这意味着要么使用 concurrent.futures 或其他一些处理处理的外部服务(甚至可以为与语言无关的东西打开大门)。在这种情况下,gevent(即 celery)的一些流行或经常使用的解决方案是什么? - 最佳实践
【问题讨论】:
-
您几乎可以在每个库中采用这种模式:bottlepy.org/docs/dev/async.html#event-callbacks。我建议
evergreen,因为它允许通过集成concurrent.futures的修改版本将协作任务(greenlets)与长时间运行的任务结合起来。
标签: python asynchronous flask gevent