问题描述
首先,我承认在这个标题中有几个到几个关键词,但我的确确实在试图以正确的方式来解决问题。这里的问题是,我似乎无法正确创建使用python多处理模块的子进程,而不会导致网页响应挂起。我已经尝试了几个最新版本的gunicorn,问题依然存在。有趣的是,这个问题从来没有在Ubuntu服务器上的问题,但现在移动应用程序到rhel6.5这个问题已经出现。这里是工作流程:-route命中
-form被提交,命中路由并触发多处理.Process()被创建,其中完成的工作是休眠30秒
- 路由看起来像打印多处理呼叫之后的打印语句一样完成,但是浏览器保持连接打开并且不完成加载(显示页面)直到完成睡眠的30秒
请注意,表单提交不是这个问题的一部分,它只是帮助查看问题的发生。
这是一个非常简单的路线和函数,它产生了这个问题:
def multi():
print'begin multi'
time.sleep(30)
print'end multi'
@ app.route('/ ():
$ b语法形式= forms.mainSyntaxForm()
语法形式。在多次调用之前,
print'
th = multiprocessing.Process(target = multi)
th.start()
多次调用后打印'
return return('multiprocesstest')
return render_template('syntax_main.html',form = syntaxForm)
经过对这个问题的深入研究和稀疏的google结果,我还没有发现任何结论。我要去尝试另一个负载平衡器来检查问题是只有gunicorn。
好的,我在Flask / UWSGI / NGINX / Linux 14.04上遇到了这个问题。
对于未来的读者来说是个好消息:我能够解决这个问题。
坏消息:我很确定这是一个可怕的黑客行为。
一些有趣的测试代码证明这将永远挂起:
$
$ b $ import $ $ $ $ $ b def spin_forever():
,而真:
time.sleep(1)
print('starting new process')
p = mp.Process(target = spin_forever)
print('created')
p.start()
print('started - generate result')
return flask.render_template_string('awesome')
如果您点击了端点/ spin-up,它将启动进程并永久挂起。很漂亮,呵呵?
基本的消息队列不能工作,除非你完全离开进程(例如,使用已经启动的消息队列不同的进程)或者不验证成功(即等待成功的ACK响应)。
简单的回答是,如果你试图验证你的子过程成功了,那你就麻烦了。我在线程之间使用内部消息队列,如果我等待成功响应,Flask服务器仍然会挂起。例如,
@ app.route('/ spin-up')
def spin_up():
put_start_message_on_queue():
而真:
如果got_success_response_from_queue():
break
time.sleep(0.1)
return flask.render_template_string('awesome')
这仍然是挂起(永远),所以我添加了第二个命令到消息队列称为'重新启动' :
$ $ p $ code $ @ app.route('/ spin-up')
def spin_up():
put_start_message_on_queue()
而真:
如果got_success_message_from_queue():
break
time.sleep(0.1)
put_restart_message_on_queue()
return flask.render_template_string 'awesome')
您必须确保restart_message在收到时会杀死现有进程,然后执行在开始新的工作之前,最小的工作量,甚至可能插入一个
time.sleep(0)
在消息处理程序中。这是一个巨大的黑客,据我所知,但它的工作一贯,只要进程可以重新启动(对不起,如果这不是你的情况...)
First I will admit that there are a few to many keywords in that title, but I am indeed really trying to capture the problem in the correct manner. The issue here is that I can not seem to be able to correctly create a sub process using the python multiprocessing module without it causing the webpage response to hang. I have tried a few recent versions of gunicorn and the problem persists. Interestingly, the problem never was an issue on ubuntu server, but now moving the application to rhel6.5 this issue has presented itself. Here is the workflow:
-route is hit-form is submitted which hits the route and triggers a multiprocessing.Process() to be created, where the work done is to sleep for 30 seconds-the route appears to finish, as a print statement after the multiprocessing call is printed, however the browser keeps the connection open and does not 'finish loading' (show the page) until the 30 seconds of sleep are finished
Note that the form submission is not part of this issue, it just helps in viewing the issue happen.
Here is a very simple route and function that produces the issue:
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)
After extended research and sparse google results for this problem, I have not found anything conclusive. I am going to try another load balancer to check is the problem is gunicorn only.
OK, so I ran into this on Flask/UWSGI/NGINX/Linux 14.04.
Good news for future readers: I was able to resolve this.Bad news: I am pretty sure this is a horrible hack.
Some interesting test code to prove that this will hang forever:
@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')
If you hit the endpoint '/spin-up' it will spin up the process and hang forever. Pretty awesome, huh?
Basic message-queues don't work unless you go fully out-of-process (i.e., use a message queue running in an already-started different process) or don't validate the success (i.e., wait for a success ACK response).
The short answer is that if you attempt to validate that your sub-process succeeded, you are in trouble. I was using an internal message queue between threads, and if I waited for my "success" response, the Flask server would still hang. E.g.,
@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')
This still hangs (forever), so instead I added a second command to the message queue called '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')
You have to ensure that the restart_message, when received kills the existing process, then does a minimal amount of work before starting the new one, potentially even inserting a
time.sleep(0)
in the message handler. THIS IS A HUGE HACK as far as I can tell, but it works consistently, and so long as the process can be restarted (sorry if that's not the case for you...)
这篇关于使用Python的Multiprocessing使响应挂在gunicorn上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!