Gunicorn,Django,Gevent:Spawned线程正在阻塞

时间:2014-07-02 01:42:27

标签: python django multithreading gunicorn gevent

我们最近使用 gevent 工作人员切换到 Gunicorn

在我们的网站上,我们有一些需要一段时间才能完成的任务。超过30秒。

序言

我们已经完成了整个芹菜的事情,但是这些任务很少运行,以至于不能让celery和redis一直运行。我们只是不想那样。我们也不想按需开始芹菜和红葡萄酒。我们想要摆脱它。 (我很抱歉这个,但我想阻止这样的答案:"为什么不使用芹菜,它太棒了!")

我们想要异步运行的任务

我正在谈论执行3000个SQL查询(插入)的任务,这些查询必须一个接一个地执行。 这种情况并非经常发生。我们仅限于同时运行其中两项任务。他们应该采取 2-3分钟

方法

现在,我们现在正在做的是利用gevent worker和gevent.spawn任务并返回响应。

问题

我发现生成的线程实际上是阻塞的。一旦返回响应,任务就会开始运行,并且在任务停止运行之前不会处理任何其他请求。这项任务将在30多岁后被枪杀timeout。 为了防止这种情况,我在每个其他SQL查询之后使用time.sleep(),因此服务器有机会响应请求,但我不觉得这是重点。

设置

我们运行gunicorn,django并使用gevent。描述的行为发生在我的开发环境中并使用1 gevent worker。在生产中,我们也只运行一名工人(现在)。此外,在任务阻塞时,运行2名工作人员似乎无助于提供更多请求。

TLDR

  • 我们认为在我们的2分钟任务中使用gevent线程是可行的 (芹菜上)
  • 我们使用gunicorn与gevent,并想知道为什么一个线程 与gevent.spawn一起产生阻止
  • 阻止意图或我们的设置是否错误?

谢谢!

3 个答案:

答案 0 :(得分:0)

在后台运行任务的一种方法是fork父进程。与Gevent不同,它不会阻止 - 你运行两个完全独立的进程。这比开始另一个(非常便宜的)greenlet慢,但在这种情况下,这是一个很好的权衡。

您的流程分为两部分,即父级和子级。在父母身上,return对Gunicorn的回应就像普通代码一样。

在孩子身上,进行长时间的处理。最后,通过执行exit的专用版本进行清理。这是一些处理和发送电子邮件的代码:

    if os.fork():
        return JsonResponse({}) # async parent: return HTTP 200
    # child: do stuff, exit quietly
    ret = do_tag_notify(
        event, emails=emails, photo_names=photo_names,
        )
    logging.info('do_tag_notify/async result={0}'.format(ret))
    os._exit(0)             # pylint: disable=W0212
    logging.error("async child didn't _exit correctly") # never happens

小心这一点。如果孩子抛出异常,即使是语法错误或未使用的变量,你也永远不会知道它!记录的父级已经消失。记录日期冗长,不要做太多。

使用fork是一个有用的工具 - 玩得开心!

答案 1 :(得分:0)

我已决定使用synchronous(标准)工作人员并使用multiprocessing库。这似乎是目前最简单的解决方案。

我还实现了一个全局滥用提供锁定的memcached缓存,因此只能运行两个任务。

答案 2 :(得分:0)

这似乎没有人在这里提出你的问题。

  

阻止意图或我们的设置是否错误?

您的设置有问题。 SQL查询几乎完全受I / O限制,不应阻止任何greenlet。您要么使用不是gevent友好的SQL / ORM库,要么代码中的其他内容导致阻塞。您不应该为这种任务使用多处理。

除非您在greenlets上明确地执行join,否则服务器响应不应该阻塞。