简体   繁体   English

使用Bottlepy-Gevent生成多个Greenlet

[英]Spawning multiple greenlets using Bottlepy-Gevent

I am new to Asynchronous programming and a following the Bottlepy-gevent tutorial here . 我是异步编程的新手,并且这里还介绍了Bottlepy-gevent教程。

I ran the program given on the page: 我运行了页面上给出的程序:

from gevent import monkey; monkey.patch_all()

from time import sleep
from bottle import route, run

@route('/stream')
def stream():
    yield 'START'
    sleep(3)
    yield 'MIDDLE'
    sleep(5)
    yield 'END'

run(host='0.0.0.0', port=8080, server='gevent')

and it works as expected when i access the URL http://localhost:8080/stream , printing START followed by MIDDLE and END at a sleep interval of 3 and 5 seconds respectively. 当我访问URL http://localhost:8080/stream时,它按预期方式工作,分别在3秒和5秒的睡眠间隔内打印STARTMIDDLEEND

As per the docs, 根据文档,

monkey patching enables gevent to prevent Python's blocking APIs (and functions like time.sleep()) from blocking the current thread, and passes the CPU to the next greenlet instead. 猴子修补使gevent能够阻止Python的阻塞API(以及诸如time.sleep()之类的函数)阻塞当前线程,并将CPU传递给下一个greenlet。

However, when I modified the above code to print the current greenlet info, I got the same greenlet instance being used for all the three yield statements. 但是,当我修改上面的代码以打印当前的greenlet信息时,我将相同的greenlet实例用于所有三个yield语句。

import gevent
from gevent import monkey
monkey.patch_all()

from time import sleep
from bottle import route, run

@route('/stream')
def stream():
    print(gevent.getcurrent())
    yield 'START '
    sleep(3)
    print(gevent.getcurrent())
    yield 'MIDDLE '
    sleep(5)
    print(gevent.getcurrent())
    yield 'END'

run(host='0.0.0.0', port=8080, server='gevent')

Console output: 控制台输出:

<Greenlet at 0x7f9fd733a9c8: _handle_and_close_when_done(<bound method WSGIServer.handle of <WSGIServer at , <bound method StreamServer.do_close of <WSGIServer, (<gevent._socket3.socket object, fd=7, family=2, t)>
<Greenlet at 0x7f9fd733a9c8: _handle_and_close_when_done(<bound method WSGIServer.handle of <WSGIServer at , <bound method StreamServer.do_close of <WSGIServer, (<gevent._socket3.socket object, fd=7, family=2, t)>
<Greenlet at 0x7f9fd733a9c8: _handle_and_close_when_done(<bound method WSGIServer.handle of <WSGIServer at , <bound method StreamServer.do_close of <WSGIServer, (<gevent._socket3.socket object, fd=7, family=2, t)>

Per the bottlepy docs, shouldn't a new greenlet instance be spawned each time the time.sleep() is executed? 根据瓶装文档,是否不应该在每次执行time.sleep()时生成一个新的greenlet实例?

Moreover, when I run a similar program without using gevent and monkey-patching, as below: 而且,当我运行类似的程序而不使用gevent和Monkey-patching时,如下所示:

from time import sleep
from bottle import route, run

@route('/stream')
def stream():
    yield 'START \n'
    sleep(3)
    yield 'MIDDLE \n'
    sleep(5)
    yield 'END'

run(host='0.0.0.0', port=8080)

I get the same response as before(START followed by MIDDLE and END at 3 and 5 sec), contrary to the Bottlepy docs' comment, in boldface below: 我得到与以前相同的响应(START之后是MIDDLE,然后在3和5秒处结束),这与Bottlepy文档的注释相反,以下为黑体字:

If you run this script and point your browser to http://localhost:8080/stream , you should see START, MIDDLE, and END show up one by one ( rather than waiting 8 seconds to see them all at once ). 如果运行此脚本并将浏览器指向http:// localhost:8080 / stream ,则应该看到START,MIDDLE和END逐一显示( 而不是等待8秒才能一次看到它们 )。

Am i missing something here? 我在这里想念什么吗?

2 Answers: 2个答案:

  • Each request from the server will spawn a new greenlet , so in the same request you'll see the same one pause and resume. 来自服务器的每个请求都将产生一个新的greenlet ,因此在同一请求中,您将看到相同的暂停和恢复。 try sending a few requests in the same time to see more greelet s print out. 尝试同时发送一些请求,以查看更多greelet的打印输出。
  • Your example works on my Mac with chrome the bottle docs state that you may need to yield more bytes on some browsers: 您的示例在使用chromeMac上运行时,bottle docs指出您可能需要在某些浏览器上产生更多字节:

    Note : Some browsers buffer a certain amount of data before they start rendering a page. 注意 :某些浏览器在开始呈现页面之前会缓冲一定数量的数据。 You might need to yield more than a few bytes to see an effect in these browsers. 您可能需要产生多个字节才能在这些浏览器中看到效果。 Additionally, many browsers have a limit of one concurrent connection per URL. 此外,许多浏览器每个URL最多只能有一个并发连接。 If this is the case, you can use a second browser or a benchmark tool (eg ab or httperf) to measure performance. 在这种情况下,您可以使用第二个浏览器或基准工具(例如ab或httperf)来衡量性能。

Per the bottlepy docs, shouldn't a new greenlet instance be spawned each time the time.sleep() is executed? 根据瓶装文档,是否不应该在每次执行time.sleep()时生成一个新的greenlet实例?

No. The Bottle docs are a little confusing there, I'm afraid. 否。恐怕瓶子的文档有些混乱。

A new greenlet is spawned for every incoming HTTP request. 为每个传入的HTTP请求生成一个新的greenlet。 The spawned greenlet then handles the entire request, from start to finish. 然后,生成的greenlet从头到尾处理整个请求。 If that greenlet yields (either explicitly or implicitly), then another greenlet is free to do some work (presumably handling some other HTTP request). 如果那个greenlet产生了(显式或隐式),那么另一个greenlet可以自由地做一些工作(大概处理其他HTTP请求)。

When you call the monkeypatched time.sleep , the greenlet that is handling your HTTP request is suspended, thereby yielding to any other active greenlets (if any). 当你调用monkeypatched time.sleep ,正在处理您的HTTP请求的greenlet被暂停,由此产生的任何其他活动的greenlets(如果有的话)。 When time.sleep returns (after the specified number of seconds) your greenlet--the very same one that was servicing your request previously--is awakened and resumes running from just after the sleep call. time.sleep返回(在指定的秒数后)时,您的Greenlet(与之前为您的请求提供服务的那个Greenlet相同)被唤醒,并从sleep调用后恢复运行。

Hope that helps! 希望有帮助!

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

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