Libxevは、クロスプラットフォームイベントループです。 Libxevは、非ブロッキングIO、タイマー、信号、イベントなど、MacOS、Windows、Linux、およびWebAssembly(ブラウザーおよびWASI)で機能する統一イベントループ抽象化を提供します。 Zigで記述されていますが、C互換性のあるAPIをエクスポートします(さらに、C APIと通信できるあらゆる言語と互換性があります)。
プロジェクトステータス:?不安定なアルファっぽい品質。機能リストは複数のプラットフォームで非常に優れていますが、不足している機能はたくさんあります。このプロジェクトは、実際の環境では十分にテストされておらず、パフォーマンスの最適化のための低い段階的な果物がたくさんあります。この時点でも、APIの互換性を約束していません。生産の準備が整っていて、高品質で一般化されたイベントループの実装が必要な場合は、Libuv、Libevなどをチェックしてください。
なぜ新しいイベントループライブラリがあるのですか?いくつかの理由。 1つは、Zigには機能のLibuvに匹敵する一般化イベントループがないと思います(ここでは「一般化」はキーワードです)。 2つ目は、IO_IRINGのデザインパターンを中心にこのようなライブラリを構築したかったのです。他のOSプリミティブの上にそのスタイルを模倣したいと思いました(この素晴らしいブログ投稿のクレジット)。 3つ目は、WebAssembly(WASIと自立型の両方)に構築できるイベントループライブラリが欲しかったのですが、Emscriptenのような非常に重いものを持ち込むことなく、既存のライブラリのAPIスタイルの目標にはあまり適していませんでした。このライブラリの動機は、主に私自身のかゆみを掻いています!
クロスプラットフォーム。 Linux( io_uring and epoll )、macos( kqueue )、webassembly + wasi( poll_oneoff 、スレッドおよび非スレッドランタイム)。 (Windowsのサポートは計画されており、近日公開予定です)
プロクターAPI。作業はLibxevイベントループに提出され、発信者は作業の準備とは対照的に、作業の完了を通知されます。
ゼロランタイム割り当て。これにより、ランタイムパフォーマンスをより予測可能にし、Libxevを組み込み環境に適したものにします。
タイマー、TCP、UDP、ファイル、プロセス。タイマー、TCP/UDPソケット、ファイル、プロセスなどと相互作用するための高レベルのプラットフォームに依存しないAPI。 Async IOをサポートしていないプラットフォームの場合、ファイル操作はスレッドプールに自動的にスケジュールされます。
一般的なスレッドプール(オプション)。一般的なスレッドプールを作成し、リソース使用率を構成し、これを使用してカスタムバックグラウンドタスクを実行できます。スレッドプールは、一部のバックエンドで使用され、信頼性の高い非ブロックAPI( kqueueを使用したローカルファイル操作など)を持たない非ブロッキングタスクを実行します。スレッドプールは、複数のスレッドとイベントループで共有され、リソースの使用率を最適化できます。
低レベルおよび高レベルのAPI。高レベルのAPIはプラットフォームに依存していますが、意見を述べた行動と柔軟性が限られています。高レベルのAPIは推奨されますが、低レベルのAPIは常に利用可能なエスケープハッチです。低レベルのAPIはプラットフォーム固有であり、Libxevユーザーが最大のパフォーマンスを絞るメカニズムを提供します。低レベルのAPIは、OSインターフェイスの上に十分な抽象化であり、顕著なパフォーマンスを犠牲にすることなく使いやすくします。
木の揺れ(zig)。これはZigの特徴ですが、Libxevなどのライブラリに大いに役立ちます。 Zigには、実際に使用する関数呼び出しと機能のみが含まれます。特定の種類の高レベルのウォッチャー(UDPソケットなど)を使用しない場合、その抽象化に関連する機能は、最終的なバイナリにまったくコンパイルされていません。これにより、Libxevは、場合によっては「膨満感」と見なされる可能性のあるオプションの「ニースへの」機能をサポートすることができますが、エンドユーザーはそれを支払う必要はありません。
依存関係。 Libxevには、実行時に組み込みのOS API以外の依存関係はありません。 CライブラリはLIBCに依存します。これにより、クロスコンパイルが非常に簡単になります。
私がまだ追加したい不足している機能がたくさんあります:
そしてもっと...
パフォーマンスの改善の余地は十分にあります。多くの最適化作業を行っていないことを完全に明確にしたいと思います。それでも、パフォーマンスは格好良いです。 Libxev APIを使用するために、Libuvのベンチマークの多くを移植しようとしました。
それらを実行するためのより良い環境があるまで、特定のベンチマーク結果を投稿することはありません。非常に広範な一般化として、他の主要なイベントループと比較してLibxevを使用した減速に気付かないはずです。これは機能ごとに異なる場合があります。問題でパフォーマンスが非常に低いことを示すことができれば、解決に興味があります。
以下の例は、Libxevを使用して単一の5Sタイマーを実行するZigとCで書かれた同一のプログラムを示しています。これはほぼ愚かなことですが、実際のユースケースではなく、図書館の全体的な感触を伝えることを意図しています。
| ジグ | c |
const xev = @import ( "xev" );
pub fn main () ! void {
var loop = try xev . Loop . init (.{});
defer loop . deinit ();
const w = try xev . Timer . init ();
defer w . deinit ();
// 5s timer
var c : xev.Completion = undefined ;
w . run ( & loop , & c , 5000 , void , null , & timerCallback );
try loop . run ( .until_done );
}
fn timerCallback (
userdata : ? * void ,
loop : * xev.Loop ,
c : * xev.Completion ,
result : xev . Timer . RunError ! void ,
) xev.CallbackAction {
_ = userdata ;
_ = loop ;
_ = c ;
_ = result catch unreachable ;
return .disarm ;
} | # include < stddef . h >
# include < stdio . h >
# include < xev . h >
xev_cb_action timerCallback ( xev_loop * loop , xev_completion * c , int result , void * userdata ) {
return XEV_DISARM ;
}
int main ( void ) {
xev_loop loop ;
if ( xev_loop_init ( & loop ) != 0 ) {
printf ( "xev_loop_init failure n " );
return 1 ;
}
xev_watcher w ;
if ( xev_timer_init ( & w ) != 0 ) {
printf ( "xev_timer_init failure n " );
return 1 ;
}
xev_completion c ;
xev_timer_run ( & w , & loop , & c , 5000 , NULL , & timerCallback );
xev_loop_run ( & loop , XEV_RUN_UNTIL_DONE );
xev_timer_deinit ( & w );
xev_loop_deinit ( & loop );
return 0 ;
} |
これらの指示は、Zigのダウンストリームユーザーのみを対象としています。 C APIをLibxevに使用している場合は、「ビルド」セクションを参照してください。
このパッケージは、Zig 0.11に導入されたZigパッケージマネージャーと連携します。このようなbuild.zig.zonファイルを作成します。
.{
. name = "my-project" ,
. version = "0.0.0" ,
. dependencies = .{
. libxev = .{
. url = "https://github.com/mitchellh/libxev/archive/<git-ref-here>.tar.gz" ,
. hash = "12208070233b17de6be05e32af096a6760682b48598323234824def41789e993432c" ,
},
},
}そしてあなたのbuild.zigで:
const xev = b . dependency ( "libxev" , .{ . target = target , . optimize = optimize });
exe . addModule ( "xev" , xev . module ( "xev" ));?ドキュメントは進行中の作業です。 ?
現在、ドキュメントには、マンページ、例、コードコメントの3つのフォームがあります。将来的には、詳細なガイドとAPIドキュメントをWebサイト形式で作成する予定ですが、現在は利用できません。
マンページは比較的詳細です! xev(7)ライブラリ全体の概要を説明します。 xev-zig(7)とxev-c(7)は、それぞれZigとC APIの概要を提供します。そこから、 xev_loop_init(3)などのAPI-Specifc Manページが利用可能です。これは現在最高のドキュメントです。
男のページを閲覧する方法は複数あります。最もすぐにフレンドリーなのは、Webブラウザーのdocs/ DirectoryのRaw Manページソースを閲覧することです。 MANページソースはマークダウンのような構文であるため、GitHubを介してブラウザで問題なくレンダリングします。
もう1つのアプローチはzig build -Dman-pagesを実行することです。Manページはzig-outで利用できます。これには、SCDOCをインストールする必要があります(これはほとんどのパッケージマネージャーで使用できます)。 Manページを作成したら、パスでレンダリングできます。
$ man zig-out/share/man/man7/xev.7
そして、最後のアプローチは、お気に入りのパッケージマネージャーを介してLibxev man 7 xevインストールすることです(利用可能な場合)。
examples/フォルダーには例があります。この例は、CとZigの両方で利用できます。ファイル拡張子を使用しているものがどれであるかを知ることができます。
例を作成するには、以下を使用してください。
$ zig build -Dexample-name=_basic.zig
...
$ zig-out/bin/example-basic
...
-Dexample-name値は、拡張機能を含むファイル名でなければなりません。
Zigコードはよくコメントされています。コードのコメントを読むのが快適な場合は、それらの中に多くの洞察を見つけることができます。ソースはsrc/ディレクトリにあります。
ビルドでは、最新のZig Nightlyをインストールする必要があります。 Libxevには、他のビルド依存関係がありません。
インストールすると、 zig build installそれ自体で完全なライブラリを構築し、 zig-outのFHS互換ディレクトリを出力します。 --prefixフラグを使用して出力ディレクトリをカスタマイズできます。
Libxevには、大規模で成長しているテストスイートがあります。現在のプラットフォームのテストを実行するには:
$ zig build test
...これにより、現在のホストプラットフォームのすべてのサポートされている機能のすべてのテストが実行されます。たとえば、Linuxでは、これは完全なIO_URINGとEPOLLテストスイートの両方を実行します。
テスト実行可能ファイルをクロスコンパイルし、ターゲットマシンにコピーして実行することにより、他のプラットフォームのテストを構築および実行できます。たとえば、以下は、LinuxのMacOSのテストをクロスコンパイルして構築する方法を示しています。
$ zig build -Dtarget=aarch64-macos -Dinstall-tests
...
$ file zig-out/bin/xev-test
zig-out/bin/xev-test: Mach-O 64-bit arm64 executableワシは特別なケースです。 WASMTIMEインストールがある場合は、WASIのテストを実行できます。
$ zig build test -Dtarget=wasm32-wasi -Dwasmtime
...