[英]RuntimeWarning: coroutine was never awaited asyncio.run in separate thread
I've built a little aiohttp based spider.我已经构建了一个基于 aiohttp 的小蜘蛛。 Here's some abbreviated code:
这是一些缩写代码:
import asyncio
from aiohttp import ClientSession
from threading import Thread
class Spider:
def __init__(self, urls):
self.urls = urls
self.start()
async def fetch(self, session, url):
async with session.get(url) as response:
await self.handle_status(response) # undefined here for brevity
return await self.render_body(response) # undefined here for brevity
async def process_urls(self):
async with ClientSession() as session:
tasks = {self.fetch(session, url) for url in self.urls}
for task in asyncio.as_completed(tasks):
raw_data = await task
data = self.extract_data(*raw_data) # sync method undefined here for brevity
await self.store_data(data) # undefined here for brevity
def start(self) -> None:
try:
asyncio.run(self.process_urls())
except RuntimeError: # loop already running
x = Thread(target=asyncio.run, args=(self.process_urls(),))
x.start()
x.join()
The start method is intended to start an asyncio loop, but if one is already running, then it starts a new loop in a new Thread. start 方法旨在启动一个 asyncio 循环,但如果一个已经在运行,那么它会在一个新线程中启动一个新循环。
The code works whether run from an existing loop or not.无论是否从现有循环运行,该代码都有效。 But if run from an existing loop (eg with pytest.mark.asyncio()), I get this warning:
但如果从现有循环运行(例如,使用 pytest.mark.asyncio()),我会收到以下警告:
RuntimeWarning: coroutine 'Spider.process_urls' was never awaited x.join()
RuntimeWarning:协程“Spider.process_urls”从未等待 x.join()
Is this warning something I should be concerned about?这个警告是我应该关注的吗?
Is there a better way to handle this that would not cause this warning?有没有更好的方法来处理这个不会导致这个警告?
I've tried loop = asyncio.get_running_loop() with loop.create_task(self.process_urls()) instead of creating a new thread, but this fails with:我试过 loop = asyncio.get_running_loop() 和 loop.create_task(self.process_urls()) 而不是创建一个新线程,但这失败了:
RuntimeError: coroutine ignored GeneratorExit
RuntimeError:协程忽略了 GeneratorExit
I've tried nest-asyncio, but my primary use case involves another library that uses uvloop, so nest-asyncio is not compatible.我试过nest-asyncio,但我的主要用例涉及另一个使用uvloop的库,所以nest-asyncio不兼容。
I admit, I can't offer you full explanation on the reasons why that warning is there but I can offer you code that is warning free:我承认,我无法为您提供有关该警告存在的原因的完整解释,但我可以为您提供无警告的代码:
def start(self) -> None:
try:
asyncio.get_running_loop()
except RuntimeError:
asyncio.run(self.process_urls())
else:
# Since the loop is already instantiated we can use it with our own
# tasks without creating another thread.
# asyncio.create_task(self.process_urls())
x = Thread(target=asyncio.run, args=(self.process_urls(),))
x.start()
x.join()
Possibly, you get RuntimeWarning
because your code creates new Thread (and BTW, that warning gets produced even when you switch to asyncio.create_task()
) during handling of the exception where "normal laws of physics" don't apply.您可能会收到
RuntimeWarning
,因为您的代码在处理“正常物理定律”不适用的异常时创建了新线程(顺便说一句,即使您切换到asyncio.create_task()
也会产生该警告)。 But again, that's only my guess so take it with a grain of salt.但同样,这只是我的猜测,所以请谨慎对待。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.