2

greenlet スロットリングを実現するために、私gevent.queue.Queueはトークン バケットを実装していました。
パターンを関数デコレータに変えました:

from functools import wraps
from timeit import default_timer
import gevent
from gevent.queue import Queue

def gevent_throttle(calls_per_sec=0):
    """Decorates a Greenlet function for throttling."""
    interval = 1. / calls_per_sec if calls_per_sec else 0
    def decorate(func):
        tq = Queue(1)
        tq.put(0.)
        @wraps(func)
        def throttled_func(*args, **kwargs):
            if calls_per_sec:
                last, current = tq.get(), default_timer()
                elapsed = current - last
                if elapsed < interval:
                    gevent.sleep(interval - elapsed)
                tq.put_nowait(default_timer())
            return func(*args, **kwargs)
        return throttled_func
    return decorate

例:

import requests
from gevent.pool import Pool

pool = Pool()

@gevent_throttle(10)
def worker(address):
    """Geocodes an address against Google Maps."""
    print address
    url='http://maps.googleapis.com/maps/api/geocode/json'
    params = dict(address=address, sensor='false')
    json = requests.get(url, params=params).json
    return json

jobs = pool.imap(worker, 'NYC LA SF Chicago Boston Austin Portland'.split())

明らかな欠点の 1 つは、ワーカーが順不同でキューからタスクを取得することです。ただし、ほとんどのユース ケースでは、ワーカー グリーンレット間で特定の順序を必要としないと思います。

他に欠点はありますか?代替手段はありますか?

4

0 に答える 0