ProactorEventLoop-ValueError:循环参数必须与Future一致

时间:2019-04-06 12:30:32

标签: python python-asyncio

我正在使用具有以下代码的异步项目(称为Broker-see git

   proxies = asyncio.Queue()
   broker = Broker(proxies)
   tasks = asyncio.gather(broker.find(types = ['HTTPS'], strict = True, limit = 10),
                               self.storeProxies(proxies))
   loop = asyncio.get_event_loop()
   loop.run_until_complete(tasks)

其中self.storeProxies是一个异步函数,其中包含

while True:
    proxy = await proxies.get()
    if proxy is None: break
    self.proxies['http://{0}:{1}'.format(proxy.host, proxy.port)] = 1

但是,我认为它与Broker部分无关(当然不确定)。

每次运行此代码时,在相当随机的成功次数之后,它会以[WinError 10038] An operation was attempted on something that is not a socket失败。然后,我尝试进行一些研究,最终得到this answer。但是当尝试使用此代码时,出现此错误:

ValueError: loop argument must agree with Future

关于如何处理此问题的任何想法?

可能有用的详细信息:

OS:Windows 10(版本1809) Python版本:3.7.1

基于Mikhail Gerasimov的回答

async def storeProxies(self, proxies):
    logger.info("IN IT!")
    while True:
        proxy = await proxies.get()
        if proxy is None: break
        self.proxies['http://{0}:{1}'.format(proxy.host, proxy.port)] = 1

async def getfetching(self, amount):
    from proxybroker import Broker

    proxies = asyncio.Queue()
    broker = Broker(proxies)
    return await asyncio.gather(
        broker.find(
            types = ['HTTP', 'HTTPS'],
            strict = True,
            limit = 10
        ),
        self.storeProxies(proxies)
    )
def fetchProxies(self, amount):
    if os.name == 'nt':
        loop = asyncio.SelectorEventLoop() # for subprocess' pipes on Windows
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()
    loop.run_until_complete(self.getfetching(amount))
    logger.info("FETCHING COMPLETE!!!!!!")
    logger.info('Proxies: {}'.format(self.proxies))

其中fetchProxies从另一个地方以一定的间隔被调用。第一次可以完美运行,但随后出现警告“失败”:

2019-04-06 21:04:21 [py.warnings] WARNING: d:\users\me\anaconda3\lib\site-packages\proxybroker\providers.py:78: DeprecationWarning: The object should be created from async function
  headers=get_headers(), cookies=self._cookies, loop=self._loop

2019-04-06 21:04:21 [py.warnings] WARNING: d:\users\me\anaconda3\lib\site-packages\aiohttp\connector.py:730: DeprecationWarning: The object should be created from async function
  loop=loop)

2019-04-06 21:04:21 [py.warnings] WARNING: d:\users\me\anaconda3\lib\site-packages\aiohttp\cookiejar.py:55: DeprecationWarning: The object should be created from async function
  super().__init__(loop=loop)

之后是一个看起来像是无限循环的行为(硬输出什么也没有卡住)。值得注意的是,在全局导入Broker时,在Gerasimov的示例中(在注释中)我也遇到了这种情况。最后,我开始看到隧道的光芒。

1 个答案:

答案 0 :(得分:0)

看看这部分:

proxies = asyncio.Queue()

# ...

loop.run_until_complete(tasks)

asyncio.Queue()创建时绑定到当前事件循环(默认事件循环或使用asyncio.set_event_loop()设置为当前事件循环)。通常只有循环对象绑定才能对其进行管理。如果更改当前循环,则应重新创建对象。许多其他asyncio对象也是如此。

为确保每个对象都绑定到新的事件循环,最好在设置和运行新的事件循环后已经创建asyncio相关的对象。看起来像这样:

async def main():
    proxies = asyncio.Queue()
    broker = Broker(proxies)
    return await asyncio.gather(
        broker.find(
            types = ['HTTPS'], 
            strict = True, 
            limit = amount
        ),
        self.storeProxies(proxies)
    )


if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
loop.run_until_complete(main())

有时(很少),您也必须在main()内放置一些导入内容。


更新:

发生问题是因为您在fetchProxies个调用之间更改了事件循环,但是Broker仅导入了一次(Python缓存导入的模块)。

Reloading Broker对我不起作用,因此我找不到比重用一次设置的事件循环更好的方法了。

替换此代码

if os.name == 'nt':
    loop = asyncio.SelectorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

与此

if os.name == 'nt':
    loop = asyncio.get_event_loop()
    if not isinstance(loop, asyncio.SelectorEventLoop):
        loop = asyncio.SelectorEventLoop() # for subprocess' pipes on Windows
        asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

PS

顺便说一句,您不必首先这样做:

if os.name == 'nt':
    loop = asyncio.SelectorEventLoop()
    asyncio.set_event_loop(loop)

Windows已默认使用SelectorEventLoop,并且不支持管道doc)。