简体   繁体   English

在使用Gunicorn和Gevent运行Flask时,请求包含请求的非阻塞请求

[英]Make a non-blocking request with requests when running Flask with Gunicorn and Gevent

My Flask application will receive a request, do some processing, and then make a request to a slow external endpoint that takes 5 seconds to respond. 我的Flask应用程序将收到一个请求,进行一些处理,然后向一个需要5秒钟响应的慢速外部端点发出请求。 It looks like running Gunicorn with Gevent will allow it to handle many of these slow requests at the same time. 看起来使用Gevent运行Gunicorn将允许它同时处理许多这些慢速请求。 How can I modify the example below so that the view is non-blocking? 如何修改下面的示例以使视图无阻塞?

import requests

@app.route('/do', methods = ['POST'])
def do():
    result = requests.get('slow api')
    return result.content
gunicorn server:app -k gevent -w 4

If you're deploying your Flask application with gunicorn, it is already non-blocking. 如果您使用gunicorn部署Flask应用程序,它已经是非阻塞的。 If a client is waiting on a response from one of your views, another client can make a request to the same view without a problem. 如果客户端正在等待您的某个视图的响应,则另一个客户端可以毫无问题地向同一视图发出请求。 There will be multiple workers to process multiple requests concurrently. 将有多个工作人员同时处理多个请求。 No need to change your code for this to work. 无需更改代码即可实现此功能。 This also goes for pretty much every Flask deployment option. 这也适用于几乎所有Flask部署选项。

First a bit of background, A blocking socket is the default kind of socket, once you start reading your app or thread does not regain control until data is actually read, or you are disconnected. 首先是一些背景,阻塞套接字是默认类型的套接字,一旦你开始阅读你的应用程序或线程在实际读取数据或断开连接之前无法重新获得控制权。 This is how python-requests , operates by default. 这就是python-requests的默认操作方式。 There is a spin off called grequests which provides non blocking reads. 有一个名为grequests ,它提供非阻塞读取。

The major mechanical difference is that send, recv, connect and accept can return without having done anything. 主要的机械差异是send,recv,connect和accept可以在没有做任何事情的情况下返回。 You have (of course) a number of choices. 你(当然)有很多选择。 You can check return code and error codes and generally drive yourself crazy. 您可以检查返回代码和错误代码,通常会让自己发疯。 If you don't believe me, try it sometime 如果你不相信我,请尝试一下

Source: https://docs.python.org/2/howto/sockets.html 资料来源: https//docs.python.org/2/howto/sockets.html

It also goes on to say: 它还继续说:

There's no question that the fastest sockets code uses non-blocking sockets and select to multiplex them. 毫无疑问,最快的套接字代码使用非阻塞套接字并选择多路复用它们。 You can put together something that will saturate a LAN connection without putting any strain on the CPU. 您可以将可以使LAN连接饱和的东西放在一起,而不会给CPU带来任何压力。 The trouble is that an app written this way can't do much of anything else - it needs to be ready to shuffle bytes around at all times. 麻烦的是,以这种方式编写的应用程序无法做任何其他事情 - 它需要随时准备好随机播放字节。

Assuming that your app is actually supposed to do something more than that, threading is the optimal solution 假设您的应用实际上应该做更多的事情,线程是最佳解决方案

But do you want to add a whole lot of complexity to your view by having it spawn it's own threads. 但是,您是否希望通过生成自己的线程来为视图添加大量复杂性。 Particularly when gunicorn as async workers ? 特别是当gunicorn作为异步工人

The asynchronous workers available are based on Greenlets (via Eventlet and Gevent). 可用的异步工作程序基于Greenlets(通过Eventlet和Gevent)。 Greenlets are an implementation of cooperative multi-threading for Python. Greenlets是Python的协作多线程的实现。 In general, an application should be able to make use of these worker classes with no changes. 通常,应用程序应该能够使用这些工作类而不进行任何更改。

and

Some examples of behavior requiring asynchronous workers: Applications making long blocking calls (Ie, external web services) 需要异步工作程序的一些行为示例:进行长阻塞调用的应用程序(即外部Web服务)

So to cut a long story short, don't change anything! 所以长话短说,不要改变任何东西! Just let it be. 随它去吧。 If you are making any changes at all, let it be to introduce caching. 如果您要进行任何更改,请使用它来引入缓存。 Consider using Cache-control an extension recommended by python-requests developers. 考虑使用由python-requests开发人员推荐的扩展控件

You can use grequests . 您可以使用grequests It allows other greenlets to run while the request is made. 它允许其他greenlet在请求时运行。 It is compatible with the requests library and returns a requests.Response object. 它与requests库兼容并返回requests.Response对象。 The usage is as follows: 用法如下:

import grequests

@app.route('/do', methods = ['POST'])
def do():
    result = grequests.map([grequests.get('slow api')])
    return result[0].content

Edit: I've added a test and saw that the time didn't improve with grequests since gunicorn's gevent worker already performs monkey-patching when it is initialized: https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/ggevent.py#L65 编辑:我添加了一个测试,看到时间没有随着问候而改善,因为gunicorn的gevent worker在初始化时已经执行了猴子修补: https//github.com/benoitc/gunicorn/blob/master/gunicorn /workers/ggevent.py#L65

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM