1

我正在使用 python 3.4.3 定期向多个 url 发送请求。这是我编写的协程(我省略了一些错误处理以简化代码):

@asyncio.coroutine
def ping(url, interval, session, *, loop):
    while True:
        try:
            with aiohttp.Timeout(interval):
                resp = yield from session.get(url)
                resp.close()

        except asyncio.TimeoutError:
            # continue sending requests anyway
            continue

        yield from asyncio.sleep(interval)

我正在ping使用asyncio.gather. 但有时当服务器响应时间过长时,我会遇到InvalidStateError异常:

Exception in callback <bound method Future.set_result of Future<CANCELLED>>(None,)
handle: Handle(<bound method Future.set_result of Future<CANCELLED>>, (None,))
Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/events.py", line 39, in _run
    self._callback(*self._args)
  File "/usr/lib/python3.4/asyncio/futures.py", line 298, in set_result
    raise InvalidStateError('{}: {!r}'.format(self._state, self))
asyncio.futures.InvalidStateError: CANCELLED: Future<CANCELLED>

该脚本继续工作,但我怎样才能使这个回溯保持沉默?这是一个错误还是我做错了什么?

我唯一的想法是,当 Web 服务器最终响应时,asyncio(或 aiohttp)会尝试将 restult 设置Future为已经取消的那个。

编辑:

这是我启动该ping协程的方式:

@asyncio.coroutine
def main(loop, rules, session):
    tasks = [ping(url, interval, session, loop=loop)
             for url, interval in rules]
    try:
        yield from asyncio.gather(*tasks, loop=loop)
    except Exception:
        print('Cancelled!', file=sys.stderr)
        traceback.print_exc()


if __name__ == '__main__':
    rules = [('http://localhost:8080/1/', 5),
             ('http://localhost:8080/2/', 10)]

    loop = asyncio.get_event_loop()
    try:
        conn = aiohttp.TCPConnector(verify_ssl=False)
        with aiohttp.ClientSession(connector=conn) as session:
            loop.run_until_complete(main(loop=loop,
                                         rules=rules,
                                         session=session))
    except KeyboardInterrupt:
        print('Interrupted. Exiting', file=sys.stderr)
4

0 回答 0