😺

Linuxでepollを使ってみる

2025/03/13に公開

昔はthreadとかがなくて(統一されてなくて)、select/pollを使って書かれたサーバーとかを良く見かけました。threadが統一され、Windowsが32bitになるとマルチスレッド全盛になってあまり見かけなくなり、nginxやnode.jsが出てきた辺りで一時期epollが持て囃されてた気がします。最近ではそんなepollの記事もメッキリ減りましたが、そろそろ私も少々使ってみるかとこんな記事を書いている次第です。

※この記事は以前Qiitaに掲載していた記事で、以下はそのマークダウンになります。
https://github.com/marudedameo2019/qiita_old_articles/blob/main/79ef80e08b7103e8331d.md

epollとは

pollの進化形で複数のfdのI/O待ちを同時に出来るAPI。パイプやソケット通信で良く使用されるもの。複数の通信相手からの入力にはスレッドを使うか非同期I/Oを使うが、後者に分類される技術。詳しくは以下から。

https://en.wikipedia.org/wiki/Epoll

使ってみる

https://github.com/marudedameo2019/trying_out_epoll/blob/bed0e3f5db9eec83303ae27722db5acf436a2605/input_timeout.cpp

何のことはない、標準入力から10バイト読んで出力するだけのプログラムです。ただ、10秒以上入力がないと勝手に終わります。epoll_で始まるapi自体の説明はどこか他所で読んでください。

普通にreadするだけではスレッドなどを使わない限り、同時に10秒待ったりとかはできません。epollを使うと、待ってる間にread可能な状態になったfdだけを知ることが出来ます。これを使うことにより、何も入力のないfdをreadしてブロックされることなく、スレッドも使わずに他の処理をすることが出来るようになります。今回は何もせずに10秒waitしていますが...。apiから明らかなように同時に複数のfdを待つ事ができますが、自明なのでその説明はしません。

簡易イベントループを書いてみる

https://github.com/marudedameo2019/trying_out_epoll/blob/bed0e3f5db9eec83303ae27722db5acf436a2605/event_loop_example.cpp

標準入力から10バイトreadする間に、10秒間数える進捗表示をし、標準入力から"stop\n"を読み込めるまで続けるプログラムです。

epollを使ってevent loopを作成し、epoll_waitのタイムアウト設定を利用してsetTimeout機能を実現しています。実際に待っているのは前回同様標準入力と、epoll_waitを止めるための制御用特殊ファイルディスクリプタです。

待ち時間の間はタイマ0ms設定のsetTimeoutで無限に進捗表示をするようにしています。グラフ部分はUnicodeの特殊な文字で書いていて、同じ行を上書きするためにANSIエスケープシーケンスを直に使っています。なので端末やフォントによってはグラフが上手く表示できないものがあります。

まとめ

epoll(LT)を使って、簡易イベントループを書いてみました。入出力は同期I/Oのままだし、イベントキューもないので、なんちゃってイベントループですが、制御の雰囲気は伝わるかもしれません。

epollはETが機能的にpollと違う部分なのですが、今回は触れていません。気になる方は調べてみるといいかもです。あと昔epollが持て囃された理由は↓が詳しかったです。

https://moriyoshi.hatenablog.com/entry/20090519/1242764245

古い(15年前)ので今も記事のとおりなのかは知りません…

おまけ ~ 本物のイベントループについて

V8エンジンなどで使用されているのは、libuvというマルチプラットフォームのライブラリです。

https://github.com/libuv/libuv

Linuxではepollが使われているそうです。今どきevent loopを真面目に実装するくらいならコチラを使いましょう。この記事でなんちゃってイベントループを書いたのは、あくまで筆者の学習のためです。

GitHubで編集を提案

Discussion