15

100 バイトは小さすぎて、すべての書き込みで大きなファイル転送が遅くなる可能性があると思いますが、1MB のようなものは多すぎるように思えます。ネットワーク経由でデータを送信するための書き込みごとの最適なバイトのチャンクについて誰か提案がありますか?

もう少し詳しく説明すると、ネットワーク接続を介してデータを送信し、そのデータの送信の進行状況を表示するものを実装しています。書き込みごとに約 100 バイトの大きなファイルを送信すると、非常に遅くなりますが、プログレス バーは非常にうまく機能します。ただし、書き込みごとに 1M で送信すると、はるかに高速になりますが、送信されるチャンクが大きくなるため、進行状況バーはうまく機能しません。

4

9 に答える 9

7

いいえ、普遍的な最適なバイト サイズはありません。

TCP パケットはフラグメンテーションの影響を受けやすく、ここから宛先までのすべてが巨大なパケット サイズの真のイーサネットであると想定するのはよいことですが、現実には、すべての個々のネットワークのパケット サイズを取得できたとしても、パケットの 1 つです。送信する各パケットは、インターネットを介して異なるパスをたどる可能性があります。

それはあなたが「解決」できる問題ではなく、普遍的な理想的なサイズはありません.

OS と TCP/IP スタックにできるだけ早くデータをフィードすると、ネットワーク接続に合わせてパケット サイズが動的に調整されます (この最適化に使用されるコードが表示されるはずです。これは非常に興味深いものです。少なくともより良いスタックで。)

ただし、クライアント/サーバー間で使用されているすべてのネットワークとスタックを制御している場合は、手動で調整を行うことができます。しかし、一般的には、その場合でも、ネットワークと送信するデータを十分に把握してから、アプローチすることをお勧めします。

-アダム

于 2008-11-20T03:45:52.563 に答える
6

可能であれば、IP スタックに処理させてください。ほとんどの OS には、すでに多くの最適化機能が組み込まれています。たとえば、Vista はさまざまなパラメータを動的に変更してスループットを最大化します。アルゴリズムが有益である可能性は低いと思います。

これは、C# のように、実際のワイヤから遠く離れた高次言語で特に当てはまります。あなたと実際の TCP/IP パケットの間に十分な層があるので、あなたのコードがスループットに与える影響は比較的少ないと思います。

最悪の場合、さまざまな状況でさまざまなメッセージ サイズを自分でテストしてください。画一的なソリューションはほとんどありません。

于 2008-11-20T03:40:32.997 に答える
5

TCP/IP over Ethernet を使用している場合、最大パケット サイズは約 1500 バイトです。それ以上を一度に送信しようとすると、データは複数のパケットに分割されてから送信されます。アプリケーション内のデータが既にパケット化されている場合は、完全なパケットを送信するときに基礎となるスタックがパケットを分割する必要がないように、1500 をわずかに下回るパケット サイズを選択することをお勧めします。たとえば、送信するたびに 1600 バイトの場合、TCP スタックは送信ごとに 2 つのパケットを送信する必要があり、2 番目のパケットはほとんど空です。これはかなり非効率的です。

そうは言っても、これがパフォーマンスに目に見える影響を与えることはあまりわかりません。

于 2008-11-20T03:55:22.840 に答える
2

あなたの問題は、非ブロッキングソケットではなくブロッキングソケットを使用していることだと思います。

ブロッキングソケットを使用して1Mのデータを送信すると、ネットワークスタックはすべてのデータがバッファに配置されるのを待つことができます。バッファがいっぱいになると、ブロックされ、プログレスバーは1M全体がバッファに受け入れられると、これにはしばらく時間がかかる場合があり、プログレスバーがジャンプします。

ただし、非ブロッキングソケットを使用する場合、使用するバッファサイズはブロックされないため、select / poll / epoll / whatever-works-on-your-platformで待機する必要があります(ただし、selectが最も移植性があります) )。このようにして、プログレスバーがすばやく更新され、最も正確な情報が反映されます。

カーネルが一部のデータをバッファリングし、反対側が実際にデータを受信する前に100%に達するため、送信者ではプログレスバーが部分的に壊れていることに注意してください。これを回避する唯一の方法は、受信者が受信したデータの量に関する応答がプロトコルに含まれている場合です。

他の人が言ったように、OSとネットワークを推測することはほとんど無駄です。ブロッキングソケットを使い続ける場合は、パケットに送信するデータが少なすぎないように、単一のパケットよりも多くのデータを含めるのに十分なサイズを選択してください。これにより、スループットが不必要に低下します。一度に少なくとも2つのパケットを含めるには、4Kのようなものを使用します。

于 2009-04-01T14:21:32.290 に答える
2

CalcChunkSize という名前の関数を作成します クラスにいくつかのプライベート変数を追加します。

Private PreferredTransferDuration As Integer = 1800 ' milliseconds, the timespan the class will attempt to achieve for each chunk, to give responsive feedback on the progress bar.
Private ChunkSizeSampleInterval As Integer = 15    ' interval to update the chunk size, used in conjunction with AutoSetChunkSize. 
Private ChunkSize As Integer = 16 * 1024           ' 16k by default  
Private StartTime As DateTime
Private MaxRequestLength As Long = 4096            ' default, this is updated so that the transfer class knows how much the server will accept      

チャンクをダウンロードするたびに、ChunkSizeSampleInterval を使用して新しいチャンクサイズを計算する時期かどうかを確認します

            Dim currentIntervalMod As Integer = numIterations Mod Me.ChunkSizeSampleInterval
            If currentIntervalMod = 0 Then
                Me.StartTime = DateTime.Now
            ElseIf currentIntervalMod = 1 Then
                Me.CalcChunkSize()
            End If

numIterations は、ダウンロード ループの外側で 0 に設定され、ダウンロードされた各チャンクが numIterations += 1 に設定された後

CalcChunkSize にこれを実行させます。

Protected Sub CalcAndSetChunkSize()
    ' chunk size calculation is defined as follows 
    ' * in the examples below, the preferred transfer time is 1500ms, taking one sample. 
    ' * 
    ' * Example 1 Example 2 
    ' * Initial size = 16384 bytes (16k) 16384 
    ' * Transfer time for 1 chunk = 800ms 2000 ms 
    ' * Average throughput / ms = 16384b / 800ms = 20.48 b/ms 16384 / 2000 = 8.192 b/ms 
    ' * How many bytes in 1500ms? = 20.48 * 1500 = 30720 bytes 8.192 * 1500 = 12228 bytes 
    ' * New chunksize = 30720 bytes (speed up) 12228 bytes (slow down from original chunk size) 
    ' 

    Dim transferTime As Double = DateTime.Now.Subtract(Me.StartTime).TotalMilliseconds
    Dim averageBytesPerMilliSec As Double = Me.ChunkSize / transferTime
    Dim preferredChunkSize As Double = averageBytesPerMilliSec * Me.PreferredTransferDuration
    Me.ChunkSize = CInt(Math.Min(Me.MaxRequestLength, Math.Max(4 * 1024, preferredChunkSize)))
    ' set the chunk size so that it takes 1500ms per chunk (estimate), not less than 4Kb and not greater than 4mb // (note 4096Kb sometimes causes problems, probably due to the IIS max request size limit, choosing a slightly smaller max size of 4 million bytes seems to work nicely) 
End Sub

次に、次のチャンクをリクエストするときに ChunkSize を使用します。

Tim_mackey による「MTOM Web サービスと .Net 2.0 を使用してチャンクでファイルを送信する」でこれを見つけ、最も効果的なチャンクサイズを動的に計算することが非常に役立つことを発見しました。

全体のソース コードはこちら: http://www.codeproject.com/KB/XML/MTOMWebServices.aspx

ここで作成します: http://www.codeproject.com/script/Membership/Profiles.aspx?mid=321767

于 2008-11-20T10:08:56.377 に答える
1

1 つ付け加えておきたいのは、特定のイーサネット接続では、小さなパケットを送信するのに、大きなパケットを送信するのと同じくらいの時間がかかるということです。他の人が言ったように:データのストリームを送信しているだけなら、システムに処理させてください。しかし、個々のショート メッセージのやり取りが心配な場合は、通常のイーサネット パケットは約 1500 バイトです。

于 2008-11-20T03:56:56.113 に答える
1

Path MTU Discoveryを使用するか、適切なデフォルト値 (つまり、1500 バイト未満)を使用する必要があります。

于 2008-11-20T04:01:22.517 に答える
0

必要な式は次のとおりです。

int optimalChunkSize = totalDataSize / progressBar1.Width;

これを使用すると、送信するチャンクごとにプログレス バーが 1 ピクセルずつ増加します。これよりも小さいチャンク サイズは、ユーザー フィードバックの観点から無意味です。

于 2008-11-20T17:52:09.873 に答える
0

スニファー (tcpdump、Wireshark など) を使用して、アップ/ダウンロードに他のソフトウェアを使用したときに達成されるパケット サイズを調べることは、もちろん、まだ行っていない場合に実行できる経験的なテストの 1 つです。それはあなたにヒントを与えるかもしれません。

于 2008-11-20T12:45:20.273 に答える