Ray*_*oal 3 python multithreading asynchronous flask
我熟悉事件服务器但不熟悉线程服务器.的REST API的一个共同特征的事件触发系统,如Node.js的+明示或龙卷风是,在处理程序,异步做回调某些I/O工作,然后返回实际的HTTP响应实现回调.在Express中,我们有类似的东西:
app.post('/products', function (req, res) {
Product.create(req.body, function (err, product) {
if (err) return res.json(400, err);
res.send(201, product);
});
});
Run Code Online (Sandbox Code Playgroud)
其中,Post.create访问数据库,该产品坚持后调用回调.无论是201还是400,都会在回调中发送响应.这使得服务器在数据库工作时可以自由地执行其他操作,但从客户端的角度来看,请求似乎需要一段时间.
假设我想在Flask中做同样的事情(这不是一个公平的服务器).如果我有一个POST处理程序来创建几个需要进行多次数据库写入的对象,可能需要几秒钟才能完成,我似乎有两个选择:
我可以立即返回202 ACCEPTED,但这会给客户带来负担,不得不检查是否所有写入都已提交.
我可以直接在处理程序中实现所有数据库写入.客户端将不得不等待几秒钟的回复,但从客户端的角度来看,它是同步和简单的.
我的问题是,如果我做#2,Flask是否足够智能阻止当前请求线程,以便在数据库写入期间可以处理其他请求?我希望服务器不会阻止这里.
顺便说一下,我做了很长时间的轮询,但是这是一个公共REST API,客户希望简单的请求和响应,所以我认为方法1或2是最好的.选项1对我来说似乎很少见,但我担心#2会阻塞服务器吗?我是对的,或者Flask(和线程服务器)是否聪明,所以我不用担心?
Flask本身(非常像express)本身并不是阻塞或非阻塞 - 它依赖于底层容器来提供操作所需的功能(从用户读取数据并向用户写入响应).如果服务器没有提供事件循环(例如mod_wsgi),那么Flask将阻止.如果服务器是非阻塞服务器(例如gunicorn),那么Flask将不会阻止.
另一方面,如果您在处理程序中编写的代码阻止Flask将阻止,即使它是在非阻塞容器上运行.
考虑以下:
app.post('/products', function (req, res) {
var response = Product.createSync(req.body);
// Event loop is blocked until Product is created
if (response.isError) return res.json(400, err);
res.send(201, product);
});
Run Code Online (Sandbox Code Playgroud)
如果您在节点服务器上运行它,您将很快将所有内容都戛然而止.即使节点本身是非阻塞的,您的代码也不是,它会阻止事件循环,阻止您处理来自此节点的任何其他请求,直到在res.jsonor 处产生循环res.send.Node的生态系统可以很容易地找到非阻塞IO库 - 在大多数其他常见环境中,您必须有意识地选择将非阻塞库用于您需要执行的IO.
大多数非事件容器使用多个线程来管理并发系统的工作负载.容器接受主线程中的请求,然后处理请求的处理以及对其一个工作线程的响应服务.工作线程执行处理请求所需的(最常阻塞的)代码并生成响应.处理代码正在运行时,该线程被阻止,无法承担任何其他工作.如果请求率超过总线程池数,则客户端开始备份,等待线程完成.
知道阻止IO阻止你的一个工人,现在的问题是"你期望有多少并发用户?" (并发意味着"在接受和处理一个请求所花费的时间跨度内发生")如果答案是"小于我的工作线程池中的线程总数"那么你就是黄金 - 你的服务器可以处理负载它的非阻塞性质决不会对稳定性构成威胁.在#1和#2之间选择主要是品味问题.
另一方面,如果上述问题的答案是"超过我的线程池中的工作总数",那么您将需要通过将用户的数据传递给另一个工作池来处理请求(通常通过队列某种方式)并使用202(列表中的选项#1 )响应请求.这将使您能够缩短响应时间,从而使您能够处理更多用户.