gevent pool.wait_available()方法的含义

时间:2012-12-17 09:33:22

标签: python gevent eventlet greenlets

看,人。我们对gevent.pool类和pool.wait_available()方法有疑问,两个代码片段

1

def fetch(url):
    print 'start fetching...', url
    data = urllib2.urlopen(url)
    print url,':',data.code

urls = ['http://www.google.ru', 'http://www.s-str.ru', 'http://www.vk.com', 'http://www.yandex.ru', 'http://www.xxx.com']

pool = Pool(2)

def producer():
    for url in urls:
        pool.spawn(fetch, url)
    pool.join()

p = gevent.spawn(producer)
p.join()

2

def fetch(url):
    print 'start fetching...', url
    data = urllib2.urlopen(url)
    print url,':',data.code

urls = ['http://www.google.ru', 'http://www.s-str.ru', 'http://www.vk.com', 'http://www.yandex.ru', 'http://www.xxx.com']

pool = Pool(2)

def producer():
    for url in urls:
        pool.wait_available()
        pool.spawn(fetch, url)
    pool.join()

p = gevent.spawn(producer)
p.join()

给我们类似的结果:

start fetching... http://www.google.ru
start fetching... http://www.s-str.ru
http://www.google.ru : 200
start fetching... http://www.vk.com
http://www.s-str.ru : 200
start fetching... http://www.yandex.ru
http://www.yandex.ru : 200
start fetching... http://www.xxx.com
http://www.vk.com : 200
http://www.xxx.com : 200

任何人都可以解释wait_available()方法的含义吗?以及它的使用情况。

=======更新======== 我已经猴子对它进行了操作,它工作正常,我只想知道 - 这是两个代码片段的区别。

2 个答案:

答案 0 :(得分:2)

如果您正在使用spawn,则

TL; DR wait_available是不必要的,因为在两种方法中都运行相同的检查。但是,如果您正在使用apply_async并且想要不提交高于池上限的线程,那么您应首先致电wait_available


对于可能稍微更清楚的解释..有几种方法可以与gevent的Pool类达成相同的目的。在池中使用spawn将阻止,直到Pool中有可用空间来运行新的greenlet。这是一个简单的例子:

import gevent.monkey
gevent.monkey.patch_all()
import gevent.pool
import time

def my_slow_function():
    time.sleep(5)

def log(text):
    print '%d : %s' % (int(time.time()), text)

if __name__ == '__main__':
    thread_pool = gevent.pool.Pool(5)
    for i in xrange(20):
        log('Submitting slow func %d' % i)
        thread_pool.spawn(my_slow_function)
    thread_pool.join()
    log('Exiting')

这个输出显示它会以5个为一组产生这些,因为池包含5个greenlet的空间:

  

1403037287:提交慢功能0
  1403037287:提交慢功能1
  1403037287:提交慢功能2
  1403037287:提交慢功能3
  1403037287:提交慢功能4
  1403037292:提交慢功能5
  1403037292:提交慢功能6
  1403037292:提交慢功能7
  1403037292:提交慢功能8
  1403037292:提交慢功能9
  1403037297:提交慢功能10
  1403037297:提交慢功能11
  1403037297:提交慢功能12
  1403037297:提交慢功能13
  1403037297:提交慢功能14
  1403037302:提交慢功能15
  1403037302:提交慢功能16
  1403037302:提交慢功能17
  1403037302:提交慢功能18
  1403037302:提交慢功能19
  1403037307:退出

正如你所看到的那样,它们以相隔大约5秒钟的5个小组的形式产生。如果您深入了解gevent代码并查看Pool对象,您可以看到调用spawn将要求锁定Pool用于跟踪运行greenlet的内部信号量。

相反,如果您使用apply_async而不是spawn尝试使用相同的代码,则会强制所有调用同时运行:

  

1403037313:提交慢功能0
  1403037313:提交慢功能1
  1403037313:提交慢功能2
  1403037313:提交慢功能3
  1403037313:提交慢功能4
  1403037313:提交慢功能5
  1403037313:提交慢功能6
  1403037313:提交慢功能7
  1403037313:提交慢功能8
  1403037313:提交慢功能9
  1403037313:提交慢功能10
  1403037313:提交慢功能11
  1403037313:提交慢功能12
  1403037313:提交慢功能13
  1403037313:提交慢功能14
  1403037313:提交慢功能15
  1403037313:提交慢功能16
  1403037313:提交慢功能17
  1403037313:提交慢功能18
  1403037313:提交慢功能19
  1403037318:退出

你可以在这里看到没有阻挡或等待,他们同时被推入。但是,如果您在for循环的开头引入wait_available(),则会返回到与spawn类似的行为。

  

1403038292:提交慢功能0
  1403038292:提交慢功能1
  1403038292:提交慢功能2
  1403038292:提交慢功能3
  1403038292:提交慢功能4
  1403038297:提交慢功能5
  1403038297:提交慢功能6
  1403038297:提交慢功能7
  1403038297:提交慢功能8
  1403038297:提交慢功能9
  1403038302:提交慢功能10
  1403038302:提交慢功能11
  1403038302:提交慢功能12
  1403038302:提交慢功能13
  1403038302:提交慢功能14
  1403038307:提交慢功能15
  1403038307:提交慢功能16
  1403038307:提交慢功能17
  1403038307:提交慢功能18
  1403038307:提交慢功能19
  1403038312:退出

再一次,查看gevent中的来源,wait_available执行与调用spawn相同的检查,{{1}}正在检查信号量以查看是否实际存在空间在游泳池里。

答案 1 :(得分:0)

使用gevent,您需要先修补标准模块。

>>> import gevent.monkey
>>> gevent.monkey.patch_all()
>>> ...
>>> p = gevent.spawn(producer)
>>> p.join()
start fetching... http://www.google.ru
start fetching... http://www.s-str.ru
http://www.google.ru : 200
start fetching... http://www.vk.com
http://www.vk.com : 200
start fetching... http://www.yandex.ru
http://www.yandex.ru : 200
start fetching... http://www.xxx.com
http://www.xxx.com : 200
http://www.s-str.ru : 200

您可以看到,pool.wait_available()可以预测。

<强>更新

Pool仅以spawn函数的相同方式工作(它将等待池中的可用“插槽”)。如果您需要提供基于Pool状态(日志记录,跟踪,监控)的其他功能 - 您肯定会使用wait_availablefree_count等功能。如果您只需要{{1新的绿色线程 - 你可以依靠spawn实现。