次のような側面に興味があります。
Boost.Asio は、ネットワーキングに重点を置いて開始されたC++ライブラリですが、その非同期I/O機能は他のリソースに拡張されています。また、Boost.AsioがBoostライブラリの一部であるため、他のBoostライブラリとの重複を防ぐために、その範囲がわずかに狭められています。たとえば、Boost.Asioは Boost.Thread が既に提供しているため、スレッドの抽象化を提供しません。
一方、 libuv は、 Node.js のプラットフォーム層になるように設計されたCライブラリです。 Windowsでは IOCP 、macOSでは kqueue 、Linuxでは epoll の抽象化を提供します。さらに、スレッド、スレッドプール、スレッド間通信などの抽象化と機能を含めるために、スコープがわずかに増加したように見えます。
コアでは、各ライブラリがイベントループと非同期I/O機能を提供します。これらは、タイマー、ソケット、非同期操作などの基本機能の一部と重複しています。 libuvはより広い範囲を持ち、スレッドと同期の抽象化、同期と非同期のファイルシステム操作、プロセス管理などの追加機能を提供します。対照的に、Boost.Asioの元のネットワークフォーカスサーフェスは、ネットワーク関連の豊富なセットを提供します。 ICMP、SSL、同期ブロックおよび非ブロック操作などの機能、および改行が受信されるまでストリームから読み取るなどの一般的なタスクの高レベル操作。
以下に、いくつかの主要な機能の簡単な比較を示します。 Boost.Asioを使用する開発者は他のBoostライブラリを利用できることが多いため、直接提供されるか実装が簡単な場合、追加のBoostライブラリを検討することを選択しました。
libuv Boost イベントループ:はいAsio スレッドプール:はいAsio +スレッド スレッド: スレッド:はいスレッド 同期:はいスレッド ファイルシステム操作: 同期:はいFileSystem 非同期:はいAsio + Filesystem タイマー:はいAsio Scatter/Gather I/O[1]:Asio ネットワーキングなし: ICMP:Asio DNS解像度:非同期のみAsio SSL:Asio TCP:非同期のみAsio UDP:非同期のみAsio Signal: 処理:はいAsio 送信:はいno IPC: UNIXドメインソケット:はいAsio Windows名前付きパイプ:はいAsio プロセス管理: 切り離し:はいProcess I/Oパイプ:はいProcess 生成:はいプロセス システムクエリ: CPU:はいいいえ ネットワークインターフェイス:はいいいえ シリアルポート:いいえはい TTY:はいいいえ 共有ライブラリの読み込み:はい拡張[2]
1. 散乱/収集I/O 。
2. Boost.Extension は、Boostへのレビューのために送信されませんでした。 here のように、著者はそれが完全であると考えています。
LibuvとBoost.Asioの両方がイベントループを提供しますが、2つの間にわずかな違いがあります。
uv_default_loop()
)を作成するのではなく、デフォルトループ(uv_loop_new()
)を使用する場合は注意が必要です。io_service
は、複数のスレッドを実行できる独自のループです。これをサポートするために、Boost.Asioは 内部ロック を実行しますが、一部のコストがかかります パフォーマンス 。 Boost.Asioのリビジョン history は、ロックを最小化するためにいくつかのパフォーマンスの改善があったことを示します。uv_queue_work
を介してスレッドプールを提供します。スレッドプールのサイズは、環境変数UV_THREADPOOL_SIZE
で設定できます。作業は、イベントループ外およびスレッドプール内で実行されます。作業が完了すると、完了ハンドラーがキューに入れられ、イベントループ内で実行されます。io_service
はio_service
の結果として簡単に機能し、複数のスレッドがrun
を呼び出すことができます。 this の例に見られるように、これはユーザーにスレッド管理と動作の責任を負わせます。EAGAIN
またはEWOULDBLOCK
の戻り値とerrnoをチェックする必要があります。uv_signal_t
型とuv_signal_*
操作を使用して、抽象化kill
とシグナル処理を提供します。kill
の抽象化を提供しませんが、その signal_set
はシグナル処理を提供します。uv_pipe_t
タイプを介して nixドメインソケット および Windows名前付きパイプ を抽象化します。local::stream_protocol::socket
または local::datagram_protocol::socket
と windows::stream_handle
に分けます。APIは言語のみに基づいて異なりますが、いくつかの重要な違いがあります。
Boost.Asio内には、操作とハンドラーの間に1対1のマッピングがあります。たとえば、各 async_write
操作は、WriteHandlerを1回呼び出します。これは多くのlibuv操作とハンドラーに当てはまります。ただし、libuvのuv_async_send
は多対1のマッピングをサポートします。複数のuv_async_send
呼び出しにより、 uv_async_cb 一度呼び出されます。
ストリーム/ UDPからの読み取り、信号の処理、タイマーの待機などのタスクを処理する場合、Boost.Asioの非同期呼び出しチェーンはもう少し明示的です。 libuvでは、特定のイベントへの関心を指定するためにウォッチャーが作成されます。その後、コールバックが提供されるウォッチャーのループが開始されます。関心のあるイベントを受け取ると、コールバックが呼び出されます。一方、Boost.Asioでは、アプリケーションがイベントの処理に関心があるたびに操作を発行する必要があります。
この違いを説明するために、Boost.Asioを使用した非同期読み取りループを以下に示します。async_receive
呼び出しが複数回発行されます。
void start()
{
socket.async_receive( buffer, handle_read ); ----.
} |
.----------------------------------------------'
| .---------------------------------------.
V V |
void handle_read( ... ) |
{ |
std::cout << "got data" << std::endl; |
socket.async_receive( buffer, handle_read ); --'
}
そして、これはlibuvを使用した同じ例です。ウォッチャーがソケットにデータがあることを確認するたびにhandle_read
が呼び出されます。
uv_read_start( socket, alloc_buffer, handle_read ); --.
|
.-------------------------------------------------'
|
V
void handle_read( ... )
{
fprintf( stdout, "got data\n" );
}
Boost.Asioの非同期呼び出しチェーンとlibuvのウォッチャーの結果として、多くの場合、メモリ割り当ては異なる時間に発生します。ウォッチャーでは、libuvは処理にメモリを必要とするイベントを受け取るまで割り当てを延期します。割り当ては、ユーザーコールバックを介して行われ、libuvの内部で呼び出され、アプリケーションの割り当て解除の責任を延期します。一方、Boost.Asio操作の多くでは、async_read
のbuffer
の場合など、非同期操作を発行する前にメモリを割り当てる必要があります。 Boost.Asioは null_buffers
を提供します。これはイベントのリッスンに使用でき、メモリが必要になるまでアプリケーションがメモリ割り当てを延期できますが、これは非推奨です。
このメモリ割り当ての違いは、bind->listen->accept
ループ内にも現れます。 libuvでは、uv_listen
は、接続を受け入れる準備ができたときにユーザーコールバックを呼び出すイベントループを作成します。これにより、アプリケーションは、接続が試行されるまでクライアントの割り当てを延期できます。一方、Boost.Asioの listen
は、 acceptor
の状態のみを変更します。 async_accept
は接続イベントをリッスンし、呼び出す前にピアを割り当てる必要があります。
残念ながら、libuvとBoost.Asioを比較する具体的なベンチマーク値はありません。ただし、リアルタイムおよびほぼリアルタイムのアプリケーションでライブラリを使用して、同様のパフォーマンスを観察しました。ハードナンバーが必要な場合、libuvの ベンチマークテスト が開始点として使用できます。
さらに、実際のボトルネックを特定するためにプロファイリングを行う必要がありますが、メモリの割り当てに注意してください。 libuvの場合、メモリ割り当て戦略は主にアロケーターコールバックに制限されます。一方、Boost.AsioのAPIはアロケーターコールバックを許可せず、代わりに割り当て戦略をアプリケーションにプッシュします。ただし、Boost.Asioのハンドラー/コールバックはコピー、割り当て、および割り当て解除できます。 Boost.Asioでは、ハンドラー用のメモリ割り当て戦略を実装するために、アプリケーションが カスタムメモリ割り当て 関数を提供できます。
Asioの開発は少なくともOCT-2004にまで遡り、20日間のピアレビューを経て2006年3月22日にBoost 1.35に受け入れられました。また、 TR2のネットワークライブラリの提案 のリファレンス実装およびAPIとしても機能しました。 Boost.Asioにはかなりの ドキュメント がありますが、その有用性はユーザーによって異なります。
APIには、かなり一貫した感触もあります。さらに、非同期操作は操作名で明示的です。たとえば、accept
は同期ブロッキングで、async_accept
は非同期です。 APIは、\r\n
が読み取られるまでストリームから読み取るなど、一般的なI/Oタスク用の無料の関数を提供します。また、0.0.0.0
の「すべてのインターフェース」アドレスを表すip::address_v4::any()
など、ネットワーク固有の詳細を隠すように注意が払われています。
最後に、Boost 1.47+は handler tracking を提供します。これはデバッグ時に便利であることが証明でき、C++ 11のサポートも可能です。
Githubグラフに基づいて、Node.jsの開発は少なくとも FEB-2009 に遡り、libuvの開発は MAR-2011 に遡ります。 vbook はlibuvの紹介に最適な場所です。 APIドキュメントは here です。
全体的に、APIはかなり一貫性があり、使いやすいです。混乱の原因になる可能性のある異常の1つは、uv_tcp_listen
がウォッチャーループを作成することです。これは、一般的にウォッチャーループの寿命を制御する関数のuv_*_start
とuv_*_stop
のペアを持つ他のウォッチャーとは異なります。また、いくつかのuv_fs_*
操作には、かなりの数の引数(最大7)があります。コールバック(最後の引数)の存在で決定される同期および非同期の動作により、同期動作の可視性が低下する可能性があります。
最後に、libuv commit history をざっと見ると、開発者が非常に活発であることがわかります。
OK。私は両方のライブラリを使用した経験があり、いくつかのことを明確にすることができます。
まず、概念的な観点から、これらのライブラリは設計がまったく異なります。規模が異なるため、アーキテクチャが異なります。 Boost.Asioは、TCP/UDP/ICMPプロトコル、POSIX、SSLなどで使用することを目的とした大規模なネットワークライブラリです。 Libuvは、主にNode.jsの IOCP のクロスプラットフォーム抽象化のための単なるレイヤーです。したがって、libuvは機能的にBoost.Asioのサブセットです(一般的な機能はTCP/UDPソケットスレッド、タイマーのみです)。そのため、いくつかの基準のみを使用してこれらのライブラリを比較できます。
新しいC++機能との統合:Asioの方が優れています(Asio 1.51はC++ 11非同期モデル、ムーブセマンティクス、可変テンプレートを広く使用しています)成熟度に関して、Asioは優れたドキュメントを備えたより安定した成熟したプロジェクトです(libuvと比較した場合)ヘッダーの説明)、インターネット上の多くの情報(ビデオトーク、ブログ: http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with -boostasio?pg = 1 など)、さらには書籍(専門家向けではありませんが、それでも: http://en.highscore.de/cpp/boost/index.html )。 Libuvにはオンラインブックが1つしかありませんが(これも良い) http://nikhilm.github.com/uvbook/index.html といくつかのビデオトークがあるため、すべての秘密を知ることは困難です(これはライブラリにはたくさんあります)。関数のより具体的な説明については、以下の私のコメントを参照してください。
結論として、それはすべてあなたの目的、あなたのプロジェクト、具体的にあなたが何をしようとしているのかに依存していると言っておくべきです。
大きな違いの1つは、Asio(Christopher Kohlhoff)の著者がC++標準ライブラリに含めるために自分のライブラリをグルーミングしていることです。 http://www.open-std.org/jtc1/sc22/wg21/docs/papers /2007/n2175.pdf および http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4370.html