プログラムをTornadoからAsyncioに変換しようとしています。最初のステップは、ここで説明する実際のasyncioイベントループを使用することです。
このアプリケーションは組み込みLinuxマシンで実行され、sysfs / gpioサブシステムを介してGPIOを使用しており、これらのGPIOのいくつかでは割り込みを待っています。次のようにして、これをTornadoIOLoopに直接統合することができました。
# 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を読み取ることができるファイルへのファイルハンドルです。イベントEPOLLPRIは、そのGPIOで割り込みが使用可能になるたびに発生します。トルネードでは、これは非常にうまく機能します。_handle_interrupt
割り込みが発生した直後に関数を呼び出します。
私の問題は、これをネイティブのasyncioイベントループに変換できなかったことです。でファイルディスクリプタを見てのドキュメント私は、ファイルディスクリプタ上の汎用イベントマスク用の時計にリーダーとライターが、何を追加するための機能を見つけます。コードがCに入るので、コードに飛び込むことはできません。ただし、Tornadoレイヤーを見て、TornadoIOLoopからasyncioIOLoopに呼び出しを変換すると、次のようになります。
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)
READフラグとWRITEフラグのみが変換され、他のすべてのフラグは無視されます。
誰かが、READイベントとWRITEイベント以外のファイル記述子のイベントを監視するためにasyncioを使用することが現在不可能であることを確認できますか?それとも私は何か間違ったことをしていて、実際に方法がありますか?
私は今、これに対する解決策を自分で見つけました。情報の私の主な情報源となったのPython -チューリップのグループで、このスレッドとコードのこの作品、私は少し採用しなければなりませんでした。
主な洞察は、POLLPRI
イベントの監視に使用できるepoll自体がファイル記述子であるということです。POLLIN
epollが監視するFDでイベントが発生するたびに、epollファイル記述子は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)
...
の場合と同様のイベントフラグフィルタリングを行うため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
READとWRITEを除くすべてのイベントがフィルタリングされていることがわかります。したがって、高レベルのインターフェイスを使用してPOLLPRIイベントを監視することはできません。したがって、低レベルのインターフェイスを使用してください。
これが人々がこの問題につまずくのに役立つことを願っています。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加