这两个函数都可用于等待一组文件中的第一个文件变得可读。
select
使用 UNIX 系统调用; asyncio.wait
使用绿色线程。每种方法理论上的优缺点是什么?它们是否使用相同的底层原语(特别是,asyncio.wait
是否以某种方式发现它正在等待文件描述符并调用select
)?
import select
devices = ["/dev/input/event6", "/dev/input/event3"]
files = [open(device) for device in devices]
first_fileno = select.select([file.fileno() for file in files], [], [])[0][0]
print([file.name for file in files if file.fileno() == first_fileno][0])
import aiofiles
import asyncio
import contextlib
async def read_and_return(file):
contents = await file.read(1)
return file, contents
async def main(devices):
async with contextlib.AsyncExitStack() as stack:
files = [await stack.enter_async_context(aiofiles.open(device, "rb")) for device in devices]
tasks = [asyncio.create_task(read_and_return(file)) for file in files]
completed, incompleted = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
file, contents = list(completed)[0].result()
print(file.name)
devices = ["/dev/input/event6", "/dev/input/event3"]
asyncio.run(main(devices))
Asyncio 旨在抽象出“select”等机制的使用以及回调的需要。使用 asyncio 的好处是能够编写协作并发代码,它只会在您编写代码时运行您的代码,不会发生突然的状态更改,并且只提供了在显式位置并行或在后台运行的机会。
select
调用是一种机制,旨在显式检查某些内容的准备情况,然后处理它 - 比 asyncio 更“低级”。
因此,我们的想法是,我们将使用更高的抽象:asyncio 机制来编写单线程并发代码,而另一种方式将重写 asyncio 已经设计的代码,并设计为以有效的方式容纳,不仅基于“选择”的 I/O,还有一系列其他并发编程机制。
例外应该是,如果您仅需要
select.select
调用,并且程序的其余部分不需要单线程并发,并且使用 asyncio 会使事情变得更加复杂(例如必须搜索特定的 async当您已经有可用的同步代码时,请使用库)。
经验法则应该是使用异步机制 - 要么是原生 asyncio,要么是像“trio”这样的替代实现 - https://trio.readthedocs.io/en/stable/