Gunicorn 无法同时并发处理多个请求

9

我正在尝试使用gunicorn及其异步工作者来处理长时间运行的请求,但我找不到任何可以使其正常运作的示例。我使用了这里的示例,但进行了微调以添加一个假延迟(休眠5秒)后才返回响应:

def app(environ, start_response):
    data = "Hello, World!\n"
    start_response("200 OK", [
        ("Content-Type", "text/plain"),
        ("Content-Length", str(len(data)))
    ])
    time.sleep(5)
    return iter([data])

然后我这样运行gunicorn:

gunicorn -w 4 myapp:app -k gevent

当我打开两个浏览器选项卡,并在两个选项卡中几乎同时输入http://127.0.0.1:8000/并发送请求时,请求似乎被依次处理 - 一个请求在5秒后返回,另一个请求在另外的5秒后返回。

问:我猜想sleep不适用于gevent?但有4个工作进程,即使工作进程的类型是“同步”,也应该有两个工作进程同时处理两个请求吗?

3个回答

15

我遇到了同样的问题,在这里发布了一个问题: Requests not being distributed across gunicorn workers。结果是,浏览器序列化访问同一页。我猜可能与缓存相关,即浏览器认为该页面很可能是可缓存的,等待它加载,发现它不是,然后再进行另一个请求,依此类推。


如此烦人,又如此简单... :( - jwg
3
感谢@CrazyCasta。我通过安装另一个浏览器并同时从两个不同的浏览器(chromium和firefox)发送请求来验证了您的答案,这些请求确实可以并行服务。 - swoop81
天啊...这让我快疯了....一直在想...为什么线程不起作用...谢谢!我刚刚做了:localhost:8000/?a=1 和 localhost:8000/?b=1 当然它现在可以工作了。 - Eric Longstreet

1

当使用gunicorn与非阻塞工作类型(如gevent)时,它将仅使用一个处理请求的进程,因此您的5秒工作按顺序执行并不奇怪。

异步工作程序在您的工作负载轻且请求速率快时非常有用,在这种情况下,gunicorn可以利用浪费在等待IO上的时间(例如,等待套接字可写以将响应写入其中),通过切换到另一个工作者来处理另一个请求。通过切换到分配给同一工作进程的另一个请求。

更新

我错了。

当使用gunicorn与非阻塞工作类型和gunicorn中的工作设置时,每个工作者都是一个进程,运行单独的队列。

因此,如果time.sleep在不同的进程上运行,则会同时运行,但是当它在同一工作进程中运行时,它将按顺序执行。

问题在于gunicorn负载均衡器可能没有将两个请求分配到两个工作进程中。您可以通过os.getpid()检查当前进程。


Gunicorn 不仅使用一个进程来处理请求,它使用你指定的数字作为 -w 标志。 - ron rothman
@ron.rothman 没错!我的解释是错误的,谢谢提醒。 - tdihp

1
尝试使用gevent.sleep代替time.sleep
奇怪的是,使用-w 4时会发生这种情况,但-k gevent是一种异步工作类型,所以gunicorn可能会将两个请求发送到同一个客户端。假设这就是发生的事情,time.sleep会锁定您的进程,除非您使用gevent.monkey.patch_all()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接