使用asyncio.wait FIRST_COMPLETED时如何处理异常?

时间:2017-11-17 14:54:08

标签: python-3.x python-asyncio aiohttp

使用asyncio.wait(coro_obj,return_when = FIRST_COMPLETED)时是否有机会处理异常?

我正试图从几个外部资源获取我的IP。但是,当其中一个提供的网址被破坏时,我无法处理该异常。当任何请求返回ip时,循环执行应该停止。

bcomp file1 file2

我可以在return_when = ALL_COMPLETED但不是FIRST_COMPLETED时捕获异常

我收到了以下错误:

import asyncio
import aiohttp
from concurrent.futures import FIRST_COMPLETED


SERVICES = [
    ('ip-api1', 'http://ip-api.com/json', 'query'),
    ('broken_api', 'http://broken', 'query'),
]


async def get_ip(session, service, url, ip_attr):
    print('fetching ip from: {}'.format(service))
    async with session.get(url) as resp:
        json_resp = await resp.json()
        ip = json_resp[ip_attr]
        return service, ip


async def get_ip_from_services():
    async with aiohttp.ClientSession() as session:
        coro_obj = [get_ip(session, service[0], service[1], service[2])
                    for service in SERVICES]
        try:
            done, pending = await asyncio.wait(coro_obj, return_when=FIRST_COMPLETED)
            result = done.pop().result()
            print(result)
            for future in pending:
                future.cancel()
        except:
            print('catched')


loop = asyncio.get_event_loop()
loop.run_until_complete(get_ip_from_services())
loop.close()

或警告

fetching ip from: ip-api1
fetching ip from: broken_api
catched
exception calling callback for <Future at 0x103839240 state=finished returned list>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/concurrent/futures/_base.py", line 297, in _invoke_callbacks
    callback(self)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/futures.py", line 419, in _call_set_state
    dest_loop.call_soon_threadsafe(_set_state, destination, source)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base_events.py", line 620, in call_soon_threadsafe
    self._check_closed()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base_events.py", line 357, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Task was destroyed but it is pending!
task: <Task pending coro=<ThreadedResolver.resolve() running at /Volumes/external/venv/lib/python3.6/site-packages/aiohttp/resolver.py:31> wait_for=<Future pending cb=[_chain_future.<locals>._call_check_cancel() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/futures.py:408, <TaskWakeupMethWrapper object at 0x103807948>()]> cb=[shield.<locals>._done_callback() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py:679]>
Task was destroyed but it is pending!
task: <Task pending coro=<get_ip() done, defined at ./run_7.py:15> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1038073d8>()]>>

1 个答案:

答案 0 :(得分:2)

我认为这是aiohttp中的一个错误,我发布了它there

你收到的异常似乎并不重要,所以你可以保留它,直到它在aiohttp中修复。如果您不想立即查看请求,请不要取消请求。

您的代码几乎没有相关说明:

1)不要将Test Failed: expected [('Rudolph, Wilma', '1-410-5313-584','wilma@olympians.com'), ('Summitt, Pat', '1-865-355-4320', 'pat@greatcoaches.com')] but got [('Rudolph, Wilma', '1-410-5313-584', 'wilma@olympians.com')] Pass concurrent.futures一起使用:这些是不同的模块。使用asyncio

2)你不仅要取消任务,还要等待它被取消(它会提升asyncio.FIRST_COMPLETED)。可以使用以下代码完成:

CancelledError

详细了解任务/取消here