【问题标题】:ProactorEventLoop - ValueError: loop argument must agree with FutureProactorEventLoop - ValueError:循环参数必须与 Future 一致
【发布时间】:2019-04-06 12:30:31
【问题描述】:

我正在使用这个异步项目(称为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

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

可能有用的细节:

操作系统:Windows 10(版本 1809) Python 版本:3.7.1

根据米哈伊尔·格拉西莫夫的回答

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)

随后出现一个看起来像无限循环的行为(硬卡在什么都不输出)。值得注意的是,在 Gerasimov(在 cmets 中)的示例中,我在全局导入 Broker 时也发生了这种情况。终于,我开始看到隧道的曙光了。

【问题讨论】:

  • 在首次导入代理之前尝试调用set_event_loop
  • @user4815162342 请看我的更新:))
  • 这仍然不是在 importing Btoker 之前。可以肯定的是,将代码移到import asyncio 之后。

标签: python python-asyncio


【解决方案1】:

看看这部分:

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()

附言

顺便说一句,您一开始就不必这样做:

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

Windows 已经默认使用SelectorEventLoop,它不支持管道 (doc)。

【讨论】:

  • 哇,非常感谢您的回答!它确实似乎改变了行为,但我没有得到很多File "d:\users\me\anaconda3\lib\asyncio\events.py", line 505, in add_reader raise NotImplementedError NotImplementedError
  • @FacPam 这是由于您设置的ProactorEventLoop。看看doc:“不支持add_reader() 和add_writer()”。恐怕你得继续使用默认的SelectorEventLoop
  • @FacPam ProxyBroker 创作者可能没有在 Windows 上测试它。在那里张贴issue 很有趣。
  • 天哪,它有效!你是真正的救世主。所以现在我只有几个问题希望你能回答:1)OP中的链接答案建议使用ProactorEventLoop,那么为什么这也适用于SelectorEventLoop? 2) 有时,在proxy = await proxies.get() 行(至少这是堆栈跟踪所声称的),我得到File "d:\users\nichlasdesktop\anaconda3\lib\asyncio\base_events.py", line 469, in _check_closed raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed - 为什么?
  • 哦不,实际上,现在没有存储代理(可能与storeProxies 中的错误有关)-self.proxies 从未包含任何元素。请让我再多偷点你的时间:))
猜你喜欢
  • 1970-01-01
  • 2018-06-28
  • 2018-10-25
  • 1970-01-01
  • 1970-01-01
  • 2017-12-28
  • 1970-01-01
  • 2010-09-12
  • 2017-04-08
相关资源
最近更新 更多