在gunicorn工人之间分享锁定

时间:2013-08-13 15:47:12

标签: python concurrency flask multiprocessing gunicorn

有没有一种很好的方法可以在gunicorn工作者之间共享多处理锁?我正在尝试用Flask编写一个json API。一些API调用将与管理正在运行的进程的python类进行交互(如用于视频转换的ffmpeg)。当我将网络工作者的数量扩大到1以上时,如何确保只有1名工作人员同时与该课程进行交互?

我最初的想法是使用multiprocessing.Lock,因此start()函数可以是原子的。我不认为我已经找到了创建Lock的正确位置,以便在所有工作人员之间共享一个:

# runserver.py
from flask import Flask
from werkzeug.contrib.fixers import ProxyFix
import dummy

app = Flask(__name__)

@app.route('/')
def hello():
    dummy.start()
    return "ffmpeg started"

app.wsgi_app = ProxyFix(app.wsgi_app)

if __name__ == '__main__':
    app.run()

这是我的虚拟操作:

# dummy.py
from multiprocessing import Lock
import time

lock = Lock()

def start():
    lock.acquire()

    # TODO do work
    for i in range(0,10):
        print "did work %s" % i
        time.sleep(1)

    lock.release()

当我刷新页面几次时,我看到每个调用的输出编织在一起。

我在这里咆哮错误的树吗?有没有更简单的方法来确保只有处理类的副本(这里只是虚拟start()方法)同时运行?我想我可能需要像celery这样的东西来运行任务(而且只使用1名工人),但这似乎对我的小项目来说有点过分了。

3 个答案:

答案 0 :(得分:6)

我试了一下,似乎工作了。我将preload_app = True放在我的gunicorn.conf中,现在锁定似乎已被共享。我仍在调查这里到底发生了什么,但现在这已经足够了,YMMV。

答案 1 :(得分:5)

按照彼得的回答,工人可以共享锁资源。

但是,最好使用try-finally块来确保始终释放锁定。

# dummy.py
from multiprocessing import Lock
import time

lock = Lock()

def start():
    lock.acquire()

    try:
        # TODO do work
        for i in range(0,10):
            print "did work %s" % i
            time.sleep(1)
    finally:
        lock.release()

答案 2 :(得分:1)

最新添加:
如果由于某种原因,使用preload_app不可行,则需要使用命名锁。这样可以确保所有进程都使用相同的锁定对象。 使用mp.Lock()将为每个进程创建一个不同的对象,取反任何值。

我看到了this package,但尚未使用。它在一台机器的范围内提供一个命名锁;这意味着同一台计算机上的所有进程都将使用相同的锁,但是在一台计算机的边界之外,此解决方案是不合适的。