我尝试在python中建立一个事件循环,主要是为了教学目的,我对涉及asyncio或类似的解决方案不感兴趣,因为我的目标实际上是学习底层的linux API。
对于类似文件的对象(管道,套接字,...),有select/poll/epoll系统调用,在python中,这些被 Package 在selectors module中,这是一个可以同时等待多个文件的简单循环:
file1 = open('/var/run/foo.sock')
file2 = open('/var/run/bar.sock')
with selectors.DefaultSelector() as selector:
selector.register(file1, selectors.EVENT_READ)
selector.register(file2, selectors.EVENT_READ)
while True:
for key, mask in selector.select():
if key.fileobj == file1:
handle_data(file1)
else:
handle_data(file2)
对于proceses,有一个wait系统调用,在python中它被 Package 在subprocess module中,这是等待单个进程终止的代码:
proc = subprocess.Popen(['/usr/bin/foo'])
proc.wait()
handle_data(proc)
我如何混合这两个进程,甚至一次等待多个进程。selector.select()
和proc.wait()
都会超时,所以我们可以将其转换为半忙循环:
file1 = open('/var/run/foo.sock')
file2 = open('/var/run/bar.sock')
proc = subprocess.Popen(['/usr/bin/foo'])
timeout = 1
with selectors.DefaultSelector() as selector:
selector.register(file1, selectors.EVENT_READ)
selector.register(file2, selectors.EVENT_READ)
while True:
for key, mask in selector.select(timeout):
if key.fileobj == file1:
handle_data(file1)
else:
handle_data(file2)
if proc:
try:
proc.wait(timeout)
handle_data(proc)
proc = None
except TimeoutExpired:
pass
我想一定有更好的办法。这通常是怎么做的?
1条答案
按热度按时间9udxz4iz1#
当我在python的asyncio中查看子监视器的不同实现时,我发现了相关的信息:
os.waitpid()
,并在完成后写入管道,管道的另一端可以添加到select循环中,这种方法似乎是最常用的。SIGCHLD
的时候,你可以写一个管道,然后再次把管道的另一端添加到select循环中,然后你可以调用process.poll()
来检查哪个进程在O(n)时间内终止了。open_pidfd()
正是我要找的。它是最干净的解决方案,但只在Linux〉= 5. 3上可用。如果你不必关心可移植性,这可能是你要走的路。