Существует ли оптимальный размер байта для отправки данных по сети? - PullRequest
11 голосов
/ 20 ноября 2008

Я предполагаю, что 100 байт слишком малы и могут замедлить передачу больших файлов при всех операциях записи, но что-то вроде 1 МБ может показаться слишком большим. У кого-нибудь есть предложения по оптимальной порции байтов на запись для отправки данных по сети?

Чтобы уточнить немного, я реализую что-то, что отправляет данные по сетевому соединению и показывает ход отправки этих данных. Я заметил, что если я отправляю большие файлы по 100 байт при каждой записи, это очень медленно, но индикатор выполнения работает очень хорошо. Однако, если я отправляю, скажем, 1M на запись, это происходит намного быстрее, но индикатор выполнения работает не так хорошо из-за отправки больших кусков.

Ответы [ 9 ]

6 голосов
/ 20 ноября 2008

Нет, универсального оптимального размера байта не существует.

TCP-пакеты подвержены фрагментации, и хотя было бы неплохо предположить, что все отсюда и до места назначения - это настоящая сеть Ethernet с огромными размерами пакетов, реальность такова, даже если вы можете получить размеры пакетов всех отдельных сетей по одному. из всех пакетов, которые вы отправляете, каждый пакет, который вы отправляете, может проходить через Интернет по другому пути.

Это не проблема, которую вы можете «решить», и нет универсального идеального размера.

Как можно быстрее подайте данные в стек ОС и TCP / IP, и он будет динамически адаптировать размер пакета к сетевым подключениям (вы должны увидеть код, который они используют для этой оптимизации - это действительно, действительно интересно По крайней мере, на лучшие стеки.)

Если вы управляете всеми используемыми сетями и стеками, а также между вашими клиентами / серверами, тогда вы можете выполнить некоторую ручную настройку. Но, как правило, даже тогда у вас должно быть достаточно хорошее представление о сети и данных, которые вы отправляете, прежде чем я предложу вам приблизиться к ней.

-Adam

6 голосов
/ 20 ноября 2008

Если можете, просто дайте стеку IP справиться с этим; в большинстве ОС уже встроена большая оптимизация. Например, Vista будет динамически изменять различные параметры, чтобы максимизировать пропускную способность; повторное угадывание алгоритма вряд ли будет полезным.

Это особенно верно для языков более высокого порядка, далеких от реального провода, таких как C #; между вами и реальными пакетами TCP / IP достаточно слоев, и я ожидаю, что ваш код окажет относительно небольшое влияние на пропускную способность.

В худшем случае протестируйте сообщения разных размеров в разных ситуациях; несколько решений универсальны для всех.

4 голосов
/ 20 ноября 2008

Если вы используете TCP / IP через Ethernet, максимальный размер пакета составляет около 1500 байт. Если вы попытаетесь отправить больше, чем это, данные будут разделены на несколько пакетов перед отправкой по проводам. Если данные в вашем приложении уже пакетированы, то вы можете выбрать размер пакета чуть менее 1500, чтобы при отправке полного пакета базовый стек не разбивал его. Например, если каждая отправляемая вами посылка имеет размер 1600 байт, стек TCP должен будет отправлять два пакета для каждой отправки, причем второй пакет в основном пустой. Это довольно неэффективно.

Сказав это, я не знаю, какое видимое влияние это окажет на производительность.

2 голосов
/ 01 апреля 2009

Я считаю, что ваша проблема в том, что вы используете блокирующие, а не неблокирующие сокеты.

Когда вы используете блокирующие сокеты и отправляете 1M данных, сетевой стек может ждать, пока все данные будут помещены в буфер, если буферы заполнены, вы будете заблокированы, а индикатор выполнения будет ждать всего 1M для принятия в буферы, это может занять некоторое время, и ваш индикатор выполнения будет нервным.

Если, однако, вы используете неблокирующие сокеты, какой бы размер буфера вы не использовали, он не будет блокироваться, и вам придется самостоятельно ждать с помощью select / poll / epoll / what-works-on-your-platform (select - это самый портативный хотя). Таким образом, ваш индикатор будет быстро обновляться и отображать наиболее точную информацию.

Обратите внимание, что у отправителя индикатор выполнения частично нарушен, поскольку ядро ​​буферизует некоторые данные, и вы достигнете 100%, прежде чем другая сторона действительно получит данные. Единственный способ обойти это, если ваш протокол включает в себя ответ на количество данных, полученных получателем.

Как уже говорили другие, второе предположение, что ОС и сеть в основном бесполезны, если вы продолжаете использовать блокирующие сокеты, выберите размер, который достаточно велик, чтобы включать больше данных, чем один пакет, чтобы вы не отправляли слишком мало данных в пакет, так как это без необходимости уменьшит вашу пропускную способность. Я бы пошел с чем-то вроде 4K, чтобы включить как минимум два пакета одновременно.

1 голос
/ 20 ноября 2008

Создайте функцию с именем 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 при запросе следующего чанка.

Я обнаружил это в «Отправке файлов в чанках с помощью веб-сервисов MTOM и .Net 2.0» Tim_mackey, и мне самому было очень полезно динамически вычислять наиболее эффективный размер чанка.

Исходный код в целом здесь: http://www.codeproject.com/KB/XML/MTOMWebServices.aspx

И автор здесь: http://www.codeproject.com/script/Membership/Profiles.aspx?mid=321767

1 голос
/ 20 ноября 2008

Вам нужно будет использовать Path MTU Discovery или использовать хорошее значение по умолчанию (т. Е. Менее 1500 байт).

1 голос
/ 20 ноября 2008

Одна вещь, которую я добавлю, состоит в том, что для данного соединения с Ethernet требуется примерно столько же времени, сколько для отправки небольшого пакета. Как уже говорили другие: если вы просто отправляете поток данных, пусть система справится с этим. Но если вы беспокоитесь об отдельных коротких сообщениях взад и вперед, типичный пакет Ethernet имеет размер около 1500 байт - если вы держите его в таком состоянии, у вас все должно быть хорошо.

0 голосов
/ 20 ноября 2008

Вот формула, которая вам нужна:

int optimalChunkSize = totalDataSize / progressBar1.Width;

Используя это, каждый отправленный вами чанк будет увеличивать индикатор выполнения на 1 пиксель. Меньший размер чанка, чем этот, не имеет смысла с точки зрения обратной связи с пользователем.

0 голосов
/ 20 ноября 2008

Один эмпирический тест, который вы можете сделать, если вы еще этого не сделали, это, конечно, использовать сниффер (tcpdump, Wireshark и т. Д.) И посмотреть, какие размеры пакетов достигаются при использовании другого программного обеспечения для загрузки / выгрузки. Это может дать вам подсказку.

...