2017-10-18 183 views
1

我想程序從龍捲風轉換爲ASYNCIO的第一步是使用實際ASYNCIO事件循環作爲described here使用Python ASYNCIO等待GPIO中斷

此應用程序在嵌入式Linux機器上運行,我使用通過sysfs/gpio subsystem的GPIO以及我正在等待中斷的某些GPIO。我能直接在此整合到龍捲風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函數。

我的問題是,我一直沒能到這個轉換爲本地ASYNCIO事件循環。在the documentation for watching file descriptors我只找到函數來添加讀者和作家,但沒有什麼可以觀察文件描述符上的通用事件掩碼。我不能深入到代碼自從進入。然而,看着龍捲風層從龍捲風IOLoop調用翻譯成ASYNCIO IOLoop好像是這樣的話:

def add_handler(self, fd, handler, events): 
    fd, fileobj = self.split_fd(fd) 
    if fd in self.handlers: 
     raise ValueError("fd %s added twice" % fd) 
    self.handlers[fd] = (fileobj, stack_context.wrap(handler)) 
    if events & IOLoop.READ: 
     self.asyncio_loop.add_reader(
      fd, self._handle_events, fd, IOLoop.READ) 
     self.readers.add(fd) 
    if events & IOLoop.WRITE: 
     self.asyncio_loop.add_writer(
      fd, self._handle_events, fd, IOLoop.WRITE) 
     self.writers.add(fd) 

只讀和WRITE標誌被翻譯,所有其他標誌被忽略。

有人能證實它是目前無法使用ASYNCIO來監視除了READ文件描述符的任何事件和寫入事件?或者我做錯了事,實際上有辦法嗎?

回答

2

我現在已經爲自己找到了解決方案。我的主要信息來源是this thread in the Python-tulip groupthis piece of code,我不得不稍微採用。

主要觀點是可以用來監視POLLPRI事件的epoll的本身就是一個文件描述符。每當epoll觀看的FD上發生事件時,epoll文件描述符將生成一個POLLIN事件,該事件可以使用asyncio與add_reader進行觀看。因此,而不是直接註冊,我們手動創建一個epoll的結構,並與ioloop註冊它,像這樣:

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

實際中斷事件,然後註冊到epoll的結構

self.epoll.register(self.gpio._value_file, select.POLLPRI) 

在這一點上,中斷事件將在_handle_interrupt函數中收到。確保實際輪詢epoll的結構在事件處理程序,否則會產生連續的讀取事件

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

,因爲他們做了類似改用高層次selectors的低級別select功能是非常重要的事件標誌過濾,如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 

可以看出,除了那讀寫所有的事件進行過濾。因此,您不能使用高級界面來觀察POLLPRI事件。因此,請使用低級別界面。

我希望這可以幫助人們解決這個問題。