3

我在 Gevent 池中执行了几十个 HTTP 请求。

目标是在请求失败时重试一次,但只重试一次。否则,它应该抛出异常。

如果失败,我将如何使用 at pool 编写支持重新运行 HTTP 请求的 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_retrykwarg at spawn_greenlet
  • 据我了解,gevent.joinall(greenlets)仅加入 map 返回的greenlets。当出现异常时,是否将原始greenlet替换为返回的新greenlet retry_once?如果不是,即使额外的greenlets仍在运行,处理是否会继续?在那种情况下,我怎么能等待所有的greenlets完成呢?

Gevent 文档非常稀缺,而且网络上似乎没有其他资源可以记录这一点,尽管这是一个相当常见的用例。因此,我不认为这是一个过于本地化的问题。

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 回答