使用Python Asyncio等待GPIO中断

2024-04-19 12:15:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图将一个程序从Tornado转换为Asyncio,第一步是使用实际的asyncioeventloop作为described here。在

这个应用程序运行在一台嵌入式Linux机器上,我通过sysfs/gpio subsystem使用gpio,在其中一些gpio上我正在等待中断。我可以通过执行以下操作将其直接集成到Tornado IOLoop中:

# Register with the queue
self.io_loop.add_handler(
    self.gpio._value_file, self._handle_interrupt, self.io_loop._EPOLLPRI | self.io_loop.ERROR
)

在代码段中,_value_file是可以读取GPIO的文件的文件句柄。只要该GPIO上的中断可用,就会触发事件EPOLLPRI。在龙卷风中,这很有效。它将在中断到来后不久调用_handle_interrupt函数。在

我的问题是,我无法将其转换为本机异步事件循环。在the documentation for watching file descriptors中,我只找到添加读卡器和写入器的函数,但没有发现文件描述符上的通用事件掩码。我无法深入研究代码,因为代码是用C语言编写的。但是,看看Tornado层将Tornado Ioop的调用转换为asyncio IOLoop,似乎是这样的:

^{pr2}$

只转换读和写标志,忽略所有其他标志。在

有人能确认目前不可能使用asyncio监视文件描述符上的任何事件(读写事件除外)?还是我做错了什么事,真的有办法?在


Tags: 文件theioselfloopgpiovalue事件
1条回答
网友
1楼 · 发布于 2024-04-19 12:15:25

我自己也找到了解决办法。我的主要信息来源是this thread in the Python-tulip group和{a2},我不得不稍微采纳它们。在

主要观点是,可用于监视POLLPRI事件的epoll本身就是一个文件描述符。每当epoll监视的FD上发生事件时,epoll文件描述符将生成一个POLLIN事件,可以使用asyncio with add_reader来观察该事件。因此,我们没有直接注册,而是手动创建一个epoll结构,并将其注册到ioloop中,如下所示:

self.epoll = select.epoll()
self.io_loop.add_reader(self.epoll.fileno(), self._handle_interrupt)

然后将实际的中断事件注册到epoll结构

^{pr2}$

此时,_handle_interrupt函数将接收到中断事件。请确保在事件处理程序中实际轮询epoll结构,否则它将连续生成读取事件

def _handle_interrupt(self):
    self.epoll.poll(0)
    ...

使用低级的select功能而不是高级的selectors是很重要的,因为它们与asyncio中的事件标志过滤类似。截取的以下代码来自selectors.EpollSelector

def register(self, fileobj, events, data=None):
    key = super().register(fileobj, events, data)
    epoll_events = 0
    if events & EVENT_READ:
        epoll_events |= select.EPOLLIN
    if events & EVENT_WRITE:
        epoll_events |= select.EPOLLOUT
    try:
        self._epoll.register(key.fd, epoll_events)
    except BaseException:
        super().unregister(fileobj)
        raise
    return key

可以看出,除了读和写之外的所有事件都被过滤掉了。因此不能使用poll高级接口来监视事件。因此,使用低级接口。在

我希望这能帮助人们在这个问题上绊倒。在

相关问题 更多 >