3

Gevent プール内で数十の HTTP リクエストを実行しています。

目標は、リクエストが失敗した場合に 1 回だけ再試行することです。それ以外の場合は、例外をスローする必要があります。

HTTP リクエストが失敗した場合に 1 回の再実行をサポートする at プールを使用して gevent コードを作成するにはどうすればよいですか?

このアプローチは機能しますか?

import requests
import gevent
from gevent.pool import Pool

pool = Pool(10)

def do_request(id):
    r = requests.get('http://example.com/%u' % id)
    if not r.status_code == 200:
        raise RuntimeError(id)

def spawn_greenlet(id, is_retry=False):
    if not is_retry:
        g = gevent.spawn(id)
        g.link_exception(retry_once)
    else:
        g = pool.spawn(id)
        g.link_exception(raise_exception)
    return g

def retry_once(greenlet):
    return spawn_greenlet(greenlet.exception.args[0])

def raise_exception(greenlet):
    if greenlet.exception:
        raise greenlet.exception
    raise RuntimeError('Unknown error in greenlet processing.')


greenlets = pool.map(spawn_greenlet, [1, 2, 3, 4, 5])
gevent.joinall(greenlets)
  • 例外引数を使用するよりも、greenlet 関数の引数を取得するクリーンな方法はありますか?
  • joinall(greenlets)内部で例外が発生した後、イベントハンドラーが呼び出されるdo_request前にメソッドが戻る可能性はありますか?retry_once
  • 同じ引数で greenlet を再起動するよりクリーンな方法はありis_retryますspawn_greenletか?
  • 私がこれを理解している限りgevent.joinall(greenlets)、マップによって返されたグリーンレットのみに参加します。例外がある場合、元の greenlet は によって返された新しいものに置き換えられretry_onceますか? そうでない場合、追加の greenlet がまだ実行されていても処理は続行されますか? その場合、すべての greenlet が終了するのをどのように待つことができますか?

Gevent のドキュメントは非常に少なく、これがかなり一般的な使用例であるにも関わらず、これをドキュメント化した Web のリソースは他にないようです。したがって、私はこれがあまりにも局所的な質問だとは考えていません。

4

1 に答える 1

2

再試行に spawn/link/link_exception を使用しないでください。通常の Python を使用するだけです。

def do_something_with_retry(*args):
    try:
      return do_something(*args)
    except Exception:
      return do_something(*args)

また、gevent.pool.Pool.map は、指定されたプール内で greenlet を自動的に生成します。これを行う必要はありません。

pool = Pool(10)
pool.map(do_something_with_retry, [1, 2, 3])

実装する必要がdo_something()あるのは、通常の Python/requests コードです。

def do_something(*args):
    return requests.get('http://gevent.org')

楽しむ!

于 2012-12-22T11:25:05.163 に答える