アプリケーションがソケットの送信バッファーに常にスペースがあることを保証できる場合、ブロック送信と非ブロック送信のパフォーマンスは同じでしょうか?このシナリオでは、どちらのアプローチにも他のアプローチに勝る利点はありますか?
3 に答える
ブロッキングと非ブロッキングの唯一の違いsend
は、カーネルがプロセスをスリープ状態にするか、を返すかEWOULDBLOCK
です。したがって、パフォーマンスの点では、違いはありません。
ただし、送信バッファに空き領域があるという理由だけで送信をブロックできないという暗黙の仮定には疑問があります。メモリに大きな負荷をかけるシステムのアイドル状態のソケットを想像してみてください。カーネルが送信バッファの物理ページを「固定」することを必ずしも期待しているわけではありません。代わりに、そのメモリを何か便利なものに使用することを期待します。そして、送信しようとすると、カーネルは送信バッファー用の空きページを取得する必要があります。そして、そのようなページが利用できない場合は、EWOULDBLOCK
(たとえば)スワップを待つのではなく、戻ることを決定する可能性があります。
さて、それは多くの「多分」と「かもしれない」であり、カーネルの内部に精通している誰かが私が間違っていると私に言うかもしれません。しかし、Linuxが今日このように動作しなくても、明日になる可能性があります。Linux以外でアプリケーションを実行することは絶対にないだろうと100%確信していますか?
だから私はそのような壊れやすい仮定で私のアプリケーションを書くことはしません。ブロッキングセマンティクスと非ブロッキングセマンティクスのどちらが自分のコードにとってより意味があるかを判断し、カーネルの内部をゲーム化しようとしないことをお勧めします。
[アップデート]
Linuxの内部を掘り下げる必要がないことを望んでいましたが、自信過剰な反対意見が私をそれに駆り立てました。
「new_segment」ラベルのnet/ipv4/tcp.cから開始します。
new_segment:
if (!sk_stream_memory_free(sk))
goto wait_for_sndbuf;
skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
if (!skb)
goto wait_for_memory;
「wait_for_sndbuf」と「wait_for_memory」の違いをご覧ください。それが私が話していることです。
「wait_for_memory」ラベルには、これが非ブロッキング送信であるかどうかに依存sk_stream_wait_memory
する値を持つへの呼び出しがあります。timeo
その関数は、次に、プロセスをスリープ状態にするか、にEAGAIN
応じて戻りますtimeo
。
【アップデート2】
私が答えている質問を明確にするために...
私はこの質問を「私のソケットの送信バッファに十分な空き領域があることがわかっている場合、そのソケットのブロッキングと非ブロッキングの間にパフォーマンスまたはその他の違いはありsend
ますか?」と解釈します。
たとえば、プロトコルが1つのメッセージを送信し、前のメッセージへの応答を受信した後にのみ新しいメッセージを送信する場合、その前提は確かに可能です。この場合、送信バッファは常に空であることがわかりますsend
。POSIX標準のSO_SNDBUF
ソケットオプションを取得および/または設定することにより、ソケットに十分な空き領域があることを知ることができます。この場合、ブロッキングsend
は非ブロッキングとは異なる動作をすることができsend
ますか?
私がPOSIX仕様を読んだところ、原則として「はい」と書かれています。Linuxのソースコードを読んだところ、実際には「はい」と書かれています。私は確かに間違っている可能性がありますが、それを実証するにはPOSIXまたはLinuxに精通している人が必要であり、これまでのところ、この質問に答えた人はいません。
[最終(?)更新]
これが、POSIXがあなたに想定を許可/要求していると私が信じていることです。
送信バッファに十分な空き領域がある場合、ブロッキングsend
は永久にブロックすることはできません。これは、calloc
十分な空き仮想メモリを使用した呼び出しが永久にブロックできないのと同じ意味です。最終的に、システムはデータを送信するために必要なリソースを見つけます。
(送信バッファがいっぱいの場合は同じではないことに注意してください。この場合send
、ソケットの受信側で何が起こっているかによっては、ブロックが永久にブロックされる可能性があります。)
ただし、送信バッファーに十分なスペースがある場合でも、ノンブロッキングは.をsend
返す可能性がありEWOULDBLOCK
ます。したがって、非ブロッキングソケットを使用する場合は、送信バッファーなどについて知っていることに関係なく、コードでこれを処理する必要があります。
送信が迅速に実行されるとは限らないことに注意してください。
たとえば、反対側のソケットがrecvを使用して読み取られない場合、バッファはいっぱいになります。
もちろん、アプリケーションの両面を作成して常に読み取る場合、パフォーマンスに関して大きな違いはないと思います。
'ソケット送信バッファに常に空きがあることを確認する'唯一の方法は、それがいっぱいになったときに送信しないことです。
一部のシステムでは、送信バッファーに余裕があるかどうかを実際に判断できます。ブロッキングモードに余裕がない場合は、書き込み可能性のためにselect()を使用できます-一部のシステムでは。他のシステムでは、余裕があるかどうかがわからないか、ブロッキングモードでselect()ができません。
このようなシステムでは、送信してブロックするか、ブロックモードを使用する以外に、適切な実装の選択肢はありません。
select()を知ることはできるがselect()を知らないシステムでは、ループしてスリープすることはできますが、スリープする時間を知ることができないため、正確にブロックするブロッキングとは異なり、長時間スリープして時間を無駄にします。適切な時間。