我正在写的数据分析任务的Web UI。
下面是它应该工作的方式:
在用户指定一些参数,如dataset
和learning rate
,我创建了一个新的task record
,则该任务的执行程序asyncly开始(执行程序可能需要很长的时间来运行),用户会被重定向至其他网页。
寻找一个后async library for python
,我开始与eventlet
,这里就是我在写flask
视图功能:
db.save(task)
eventlet.spawn(executor, task)
return redirect("/show_tasks")
通过上面的代码,执行者根本不执行。
什么可能是我的代码的问题吗? 或者,也许我应该尝试别的东西吗?
你需要修补一些系统库,以便使eventlet工作。 下面是一个最小的工作示例(也为依据 ):
#!/usr/bin/env python
from flask import Flask
import time
import eventlet
eventlet.monkey_patch()
app = Flask(__name__)
app.debug = True
def background():
""" do something in the background """
print('[background] working in the background...')
time.sleep(2)
print('[background] done.')
return 42
def callback(gt, *args, **kwargs):
""" this function is called when results are available """
result = gt.wait()
print("[cb] %s" % result)
@app.route('/')
def index():
greenth = eventlet.spawn(background)
greenth.link(callback)
return "Hello World"
if __name__ == '__main__':
app.run()
更多的是:
- http://eventlet.net/doc/patching.html#monkey-patch
一个写像Eventlet图书馆所面临的挑战是,内置的网络库本身不支持的那种合作得到我们所需要的。
当你被赋予了直接的解决方案,我会尽量回答你第一个问题,并解释为什么按照预期的代码不起作用。
披露:我目前保留Eventlet。 此注释将包含一些简化,以适应合理的规模。
简介合作多线程
有两种方法可以做到多线程和Eventlet利用合作的方式。 其核心是Greenlet库基本上允许你创建独立的“执行上下文”。 有人可能认为,这种情况下所有的局部变量的冻结状态,一个指向下一条指令。 基本上, 多线程=上下文+调度器 。 Greenlet提供上下文,所以我们需要一个调度,这是令哪些情况下应该马上占用CPU决定。 事实证明,做决策,我们还应该运行一些代码。 这意味着一个单独的上下文(绿线)。 这种特殊的绿色线程被称为Eventlet代码库中的集线器 。 调度保持有序集合了需要尽快运行环境的- 运行队列 ,并设置在等待的东西(如网络IO或时间有限的睡眠)来完成的上下文。
但由于我们正在做合作多任务,一个上下文将无限期地,除非明确规定产生了另一个执行。 这将是节目的很伤心风格,也被定义与现有的库不兼容(指着他们,知道,谁); 还等什么Eventlet所做的就是提供通用模块的绿色版本,以这样的方式改变了他们切换到集线器,而不是阻止了一切。 然后,一段时间后可能会在其它绿色线程或集线器的等待换外部事件的实现中度过,在这种情况下,中心将发起该事件切换到绿色线程-它会继续执行。
结束。 现在回到你的问题。
什么eventlet.spawn
实际上做:它会创建一个新的执行上下文。 基本上,在存储器中分配对象。 此外,它告诉调度程序把这个背景下进入运行队列中 ,以便在第一可能的时候 ,集线器将切换到新生成的功能。 您的代码不提供这样的时刻。 有没有地方,你明确地放弃执行到其它绿色线程,为Eventlet这通常是通过做eventlet.sleep()
而且,由于不使用通用模块的绿色版本,没有机会当其他代码等待隐含屈服。 最合适的(如果不是唯一的一个)的地方将是你的WSGI服务器的接受循环:它应该给其他绿色线程机会在等待下一个请求运行。 在第一次答复中提到eventlet.monkey_patch()
仅仅是一个方便的方式来取代所有(或子集)及其相应的绿色版本的通用模块。
在整体设计在独立的部分不需要的意见 ,很容易忽略。 当且仅当您正在构建抗错误的软件,你通常要限制产生的线程执行时间(包括但不限于“绿色”)和流程,至少报告(日志)或响应其未处理的错误。 在提供的代码,您催生绿色线程,在技术上可以在下一时刻运行,或五分钟后(同样,因为没有人放弃CPU)或失败,未处理的异常。 幸运的是,Eventlet提供了两个问题两种解决方案: 超时 with_timeout()允许限制等待时间(记住,如果它不屈服,你不可能把它限制)和GreenThread.link()来捕获所有异常。 它可能是很有诱惑力(这是对我来说)再加注到有异常“主”的代码,并link()
允许容易,但考虑到例外将从睡眠提高和IO要求-地方,你屈服于枢纽。 这可能会提供一些真正的直觉回溯。
Eventlet可能确实是适合你的目的,但它不只是适合与任何旧的应用; Eventlet要求它在所有应用程序的I / O控制。
您可以逃脱无论是
开始在另一个线程Eventlet的主循环,甚至
不使用Eventlet,只是产卵在另一个线程你的任务。
芹菜可以是另一种选择。