使用python';s的多处理使响应挂起在gunicorn上

使用python';s的多处理使响应挂起在gunicorn上,python,flask,multiprocessing,gunicorn,Python,Flask,Multiprocessing,Gunicorn,首先,我承认在这个标题中有一些到很多的关键词,但我确实试图以正确的方式抓住这个问题。这里的问题是,如果不导致网页响应挂起,我似乎无法使用python多处理模块正确创建子进程。我尝试了gunicorn的几个最新版本,但问题依然存在。有趣的是,这个问题在ubuntu服务器上从来都不是问题,但是现在将应用程序移动到rhel6.5这个问题已经出现了。以下是工作流程: -路线被击中了 -表单被提交,点击路由并触发要创建的multiprocessing.Process(),其中完成的工作是睡眠30秒 -在打

首先,我承认在这个标题中有一些到很多的关键词,但我确实试图以正确的方式抓住这个问题。这里的问题是,如果不导致网页响应挂起,我似乎无法使用python多处理模块正确创建子进程。我尝试了gunicorn的几个最新版本,但问题依然存在。有趣的是,这个问题在ubuntu服务器上从来都不是问题,但是现在将应用程序移动到rhel6.5这个问题已经出现了。以下是工作流程:

-路线被击中了 -表单被提交,点击路由并触发要创建的multiprocessing.Process(),其中完成的工作是睡眠30秒 -在打印多处理调用后,路由显示为“完成”,这是一条打印语句,但是浏览器会保持连接打开,直到30秒睡眠结束后才会“完成加载”(显示页面)

请注意,表单提交不是此问题的一部分,它只是有助于查看问题的发生

以下是产生问题的非常简单的路线和功能:

def multi():
    print 'begin multi'
    time.sleep(30)
    print 'end multi'

@app.route('/multiprocesstest', methods=['GET','POST'])
def multiprocesstest():

    syntaxForm = forms.mainSyntaxForm()

    if syntaxForm.validate_on_submit():
        print 'before multi call'
        th = multiprocessing.Process(target=multi)
        th.start()
        print 'after multi call'
        return redirect('multiprocesstest')

    return render_template('syntax_main.html', form=syntaxForm)

在对这个问题进行了广泛的研究和稀疏的谷歌搜索结果之后,我还没有发现任何结论。我将尝试另一个负载平衡器来检查问题是否仅限于gunicorn

好的,所以我在Flask/UWSGI/NGINX/Linux 14.04上遇到了这个问题

对未来的读者来说,好消息是:我能够解决这个问题。 坏消息:我敢肯定这是一次可怕的黑客攻击

一些有趣的测试代码证明这将永远挂起:

@app.route('/spin-up')
def spin_up():
  import multiprocessing as mp
  def spin_forever():
    while True:
      time.sleep(1)

  print('starting new process')
  p = mp.Process(target=spin_forever)
  print('created')
  p.start()
  print('started--generating result')
  return flask.render_template_string('awesome')
如果您点击端点“/spin up”,它将使进程加速并永远挂起。非常棒,是吗

除非您完全脱离流程(即,使用在已启动的不同流程中运行的消息队列)或不验证成功(即,等待成功确认响应),否则基本消息队列无法工作

简单的回答是,如果您试图验证您的子流程是否成功,那么您就有麻烦了。我在线程之间使用一个内部消息队列,如果我等待“成功”响应,Flask服务器仍然会挂起。例如:

@app.route('/spin-up')
def spin_up():
  put_start_message_on_queue():
  while True:
    if got_success_response_from_queue():
      break
    time.sleep(0.1)
  return flask.render_template_string('awesome')
这仍然挂起(永远挂起),因此我在消息队列中添加了第二个名为“restart”的命令:

@app.route('/spin-up')
def spin_up():
  put_start_message_on_queue()
  while True:
    if got_success_message_from_queue():
      break
    time.sleep(0.1)
  put_restart_message_on_queue()
  return flask.render_template_string('awesome')
您必须确保在收到restart_消息时终止现有进程,然后在启动新进程之前执行最少的工作,甚至可能插入

time.sleep(0)

在消息处理程序中。据我所知,这是一个巨大的黑客攻击,但它的工作原理是一致的,只要进程可以重新启动(对不起,如果你不是这样的话…)用
多处理替换
多处理。dummy
可能会解决这个问题,因为
gunicorn
多处理
都是多处理模块,当您试图在一个进程内调用多个进程时可能会导致问题。

您使用的是哪种工作线程?我已经尝试过了gevent和sync工作者。我还尝试了uwsgi的相同示例,其中包含close-on-exec和close-on-exec2选项,具有相同的问题。如果您使用web,则工作队列而不是多处理。芹菜、RQ等。我同意@JoeDoherty的观点,将工作提交给工人/消费者处理任务的队列。查看kombu,它是一个amqp包装器和daemonicle,用于创建侦听队列的工作进程。这就是我正在使用的。