Dyl*_*lee 5 python asynchronous list python-3.x python-asyncio
我有一个运行 asyncio 事件循环的 python 脚本,我想知道如何在不阻塞事件循环的情况下迭代一个大列表。从而保持循环运行。
我试着做一个自定义类__aiter__,并__anext__没有工作,我也试着做一个async function能产生结果,但它仍然块。
目前:
for index, item in enumerate(list_with_thousands_of_items):
# do something
Run Code Online (Sandbox Code Playgroud)
我试过的自定义类:
class Aiter:
def __init__(self, iterable):
self.iter_ = iter(iterable)
async def __aiter__(self):
return self
async def __anext__(self):
try:
object = next(self.iter_)
except StopIteration:
raise StopAsyncIteration
return object
Run Code Online (Sandbox Code Playgroud)
但这总是导致
TypeError: 'async for' received an object from __aiter__ that does not implement __anext__: coroutine
Run Code Online (Sandbox Code Playgroud)
在async function我做了事件循环是一种作品,但仍块:
TypeError: 'async for' received an object from __aiter__ that does not implement __anext__: coroutine
Run Code Online (Sandbox Code Playgroud)
正如@deceze 指出的那样,您可以使用await asyncio.sleep(0)显式地将控制权传递给事件循环。但是,这种方法存在问题。
大概这个列表非常大,这就是为什么你需要特殊的措施来解除事件循环的阻塞。但是如果列表如此之大,强制每个循环迭代都让步给事件循环会大大减慢它的速度。当然,您可以通过添加计数器并仅等待 wheni%10 == 0或 wheni%100 == 0等来缓解这种情况。但是,您必须就放弃控制的频率做出任意决定(猜测)。如果你太频繁地让步,你就会减慢你的功能。如果你的 yield 太少,你就会使事件循环无响应。
这可以通过使用 来避免run_in_executor,正如 RafaëlDera 所建议的那样。run_in_executor接受阻塞函数并将其执行卸载到线程池。它立即返回一个可以await在 asyncio 中编辑的未来,一旦可用,其结果将是阻塞函数的返回值。(如果阻塞函数引发,异常将改为传播。)这await将挂起协程,直到函数返回或在其线程中引发,同时允许事件循环保持完整功能。由于阻塞函数和事件循环在单独的线程中运行,因此该函数不需要做任何事情来允许事件工作运行——它们独立运行。甚至 GIL 在这里也不是问题,因为 GIL 确保控制在线程之间传递。
随着run_in_executor你的代码看起来是这样的:
def process_the_list():
for index, item in enumerate(list_with_thousands_of_items):
# do something
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, process_the_list)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
987 次 |
| 最近记录: |