Python falcon和异步操作

时间:2014-12-04 14:55:52

标签: python falconframework

我正在使用python3 + falcon组合编写API。

在我可以向客户端发送回复的方法中有很多地方,但是由于一些繁重的代码会执行DB,i / o操作等,它必须等到繁重的部分结束。

例如:

class APIHandler:                                                                      
  def on_get(self, req, resp):
    response = "Hello"
    #Some heavy code
    resp.body(response)

我可以在第一行代码发送“Hello”。我想要的是在后台运行繁重的代码并发送响应,无论重型部件何时完成。

Falcon没有任何内置的异步功能,但他们提到它可以像gevent一样使用。我还没有找到任何关于如何将这两者结合起来的文件。

4 个答案:

答案 0 :(得分:7)

客户端库对异步操作有不同的支持,因此决策通常取决于您的特定后端客户端最好支持哪种异步方法,以及您希望使用哪种WSGI服务器。另请参阅下面的一些更常见的选项...

对于不支持异步交互模型的库,无论是本机还是通过某种子类化机制,都可以将任务委托给线程池。对于特别长时间运行的任务(即大约几秒或几分钟),芹菜不是一个糟糕的选择。

对WSGI(和Falcon)应用程序的一些常见异步选项的简要调查:

  • Twisted。支持显式异步样式,可能是最成熟的选项。为了与像Falcon这样的WSGI框架集成,有twisted.web.wsgicrochet
  • asyncio。借用Twisted的许多想法,但利用Python 3语言功能提供更清晰的界面。从长远来看,这可能是最干净的选择,但需要改进WSGI接口(另请参阅pulsar's extension to PEP-3333作为一种可能的方法)。在撰写本文时,asyncio生态系统相对年轻; the community仍在尝试各种各样的接口,模式和工具方法。
  • eventlet。支持一种旨在使异步代码看起来同步的隐式样式。一种方法是通过猴子修补标准库中的I / O模块来实现这一点。有些人不喜欢这种方法,因为它掩盖了异步机制,使边缘情况更难调试。
  • gevent。与eventlet类似,虽然有点现代。 uWSGI和Gunicorn都支持对标准库进行修补的gevent worker类型。

最后,有可能将Falcon扩展为本机支持twisted.web或asyncio(ala aiohttp),但我认为还没有人尝试过它。

答案 1 :(得分:3)

我使用Celery进行异步相关的工作。我不知道gevent。看看这个http://celery.readthedocs.org/en/latest/getting-started/introduction.html

答案 2 :(得分:2)

我认为这里有两种不同的方法:

  1. 任务经理(如芹菜)
  2. 异步实现(如gevent)
  3. 你们每个人所取得的成就是不同的。使用Celery,您可以做的是运行同步计算响应所需的所有代码,然后在后台运行任何其他操作(如保存到日志)。这样,响应应该更快。

    使用gevent,您实现的是并行执行处理程序的不同实例。因此,如果您只有一个请求,则您不会发现响应时间有任何差异,但如果您有数千个并发请求,则性能会更好。原因在于,如果没有gevent,当代码执行IO操作时,它会阻止该进程的执行,而使用gevent时,CPU可以在IO操作等待时继续执行其他请求。

    设置gevent比设置Celery容易得多。如果你正在使用gunicorn,你只需安装gevent并将worker类型更改为gevent。另一个优点是您可以并行化响应中所需的任何操作(例如从数据库中提取响应)。在Celery中,您无法在响应中使用Celery任务的输出。

    我建议,首先使用gevent,并考虑在以后添加Celery(并且同时添加它们):

    • 响应中不需要使用Celery处理的任务的输出
    • 您的芹菜任务有不同的机器,或者服务器的使用有一些高峰和一些空闲时间(如果您的服务器一直处于100%的状态,那么您在使用Celery时无法获得任何好处)
    • Celery任务的工作量,值得使用Celery

答案 3 :(得分:0)

您可以将multiprocessing.Processdeamon=True结合使用以运行守护进程并立即将响应返回给调用者:

from multiprocessing import Process

class APIHandler:

  def on_get(self, req, resp):
    heavy_process = Process(  # Create a daemonic process
        target=my_func,
        daemon=True
    )
    heavy_process.start()
    resp.body = "Quick response"


# Define some heavy function
def my_func():
    time.sleep(10)
    print("Process finished")

您可以通过发送GET请求进行测试。您将立即得到响应,十秒钟后,您将在控制台中看到打印的消息。