在 gunicorn 工人之间共享一把锁

Posted

技术标签:

【中文标题】在 gunicorn 工人之间共享一把锁【英文标题】:Sharing a lock between gunicorn workers 【发布时间】:2013-08-13 15:47:12 【问题描述】:

有没有在 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 个工人),但这对于我的小项目来说似乎有点过分了。

【问题讨论】:

【参考方案1】:

我尝试了一些东西,它似乎有效。我把preload_app = True 放在我的gunicorn.conf 中,现在锁似乎是共享的。我仍在调查这里到底发生了什么,但现在这已经足够好了,YMMV。

【讨论】:

为什么会这样?在worker进程中获取锁时,不会触发copy-on-write,也就是说锁不再在worker之间共享了吗?【参考方案2】:

按照peterw的回答,workers可以共享锁资源。

但是,最好使用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()

【讨论】:

为了让这个更pythonic,使用with lock:上下文管理器,它相当于你的try-finally(见docs)【参考方案3】:

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

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

【讨论】:

什么是named lock?我在文档中找不到。 我支持NamedAtomicLock 的推荐。我正在使用它来序列化在 gunicorn 下运行的 Dash 应用程序中的回调。在 Linux 上,gunicorn 使用 fork,所以 mp.Lock() 将不起作用。 另请参阅具有相同建议的此 *** 线程,***.com/a/64534798/1135316 @cclauss “命名锁”或“命名互斥锁”是进程间锁的通用名称。

以上是关于在 gunicorn 工人之间共享一把锁的主要内容,如果未能解决你的问题,请参考以下文章

gunicorn 不能与一个以上的工人一起运行

使用 --preload 在 gunicorn 中的工作人员之间共享内存

Gunicorn 多个烧瓶工人和绑定任务 celery

在 Gunicorn / Flask 应用程序中的进程之间共享静态全局数据

Gunicorn 在多处理进程和工作进程之间共享内存

工人之间如何共享螺栓和喷口?