2009-02-24 2 views
2

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

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

Другой метод, который я видел, использует один большой байтовый массив для всей программы. Идея очереди все еще применяется, но вместо этого она представляет собой очередь целых чисел, которые определяют срез (смещение) массива байтов для использования. Если запрос был запрошен и больше не осталось в очереди, массив должен быть изменен.

Какой из них является лучшим решением для масштабируемого сервера? Мой инстинкт заключается в том, что было бы дешевле использовать много байт-массивов, потому что я предполагаю, что изменение размера массива по мере необходимости (даже если мы будем выделять его крупными кусками) будет довольно дорогостоящим, особенно когда оно станет большим. Использование нескольких массивов также кажется более интуитивным - есть ли какое-то преимущество в использовании одного массива, о котором я не думаю?

ответ

5

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

Решение одного массива также является более сложным для реализации. Хорошо, что решение с одним массивом позволяет вам выдавать куски переменного размера, но это происходит за счет существенного переопределения malloc: работа с фрагментацией и т. Д. И т. Д., В которые вы не должны попасть.

Решение с несколькими массивами позволяет инициализировать пул с N количеством буферов и легко управлять ими простым способом. Определенно подход, который я бы рекомендовал.

2

Я бы не предложил вариант изменения размера. Начните простую и проделайте свой путь. Хорошая старта станет очередью байтовых буферов, которая получает новый, добавленный к концу, когда он будет исчерпан. Вам, вероятно, придется обратить внимание на проблемы с потоками, поэтому мой совет будет заключаться в использовании чужой поточной реализации очереди.

Далее вы можете взглянуть на более сложные «указатели» на массив большого байтового массива, за исключением того, что мой совет будет состоять в том, чтобы иметь очередь размером 4k/16k (определенная мощность в два раза больше размера страницы) вы индексируете, и когда он заполнен, вы добавляете еще один большой кусок в очередь. На самом деле, я не рекомендую этого вообще из-за сложности и сомнительного выигрыша в производительности.

Запустите простую, проделайте свой путь вверх. Пул буферов, сделайте его потокобезопасным, посмотрите, нужно ли вам что-нибудь еще.

2

Еще одно голосование за несколько буферов, но с добавлением, что, поскольку вы делаете асинхронно, вам нужно убедиться, что ваша очередь является потокобезопасной. По умолчанию Queue<T> коллекция определенно не threadsafe.

SO пользователь и работник MS JaredPar имеет хорошую реализацию очереди поточно здесь:
http://blogs.msdn.com/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx

+0

Хороший звонок, с обязательным предупреждением не делать такие вещи, как «if (queue.Count> 0) {... dequeue ...}». – user7116

+0

Прочтите ссылку: этот конкретный сценарий является одной из целей проектирования представленной реализации ThreadsafeQueue. –

1

Если вы используете один буфер вам нужна стратегия того, как быстро она должна расти по мере необходимости. Если вы вырастите его небольшими приращениями, вам придется часто это делать и часто копировать все данные. Если вы вырастите его большими приращениями (например, следующий размер в 1,5 раза превышает предыдущий), вы рискуете столкнуться с ситуацией, когда вы получите «Недостаточно памяти», просто пытаясь вырастить буфер. Это беспроигрышный выбор для масштабируемой системы. Вот почему предпочтительным является повторное использование небольших буферов.

1

С кучей мусора, вы всегда должны отдавать предпочтение маленьким буферам правильного размера, которые имеют короткий срок службы. Распределитель кучи .NET составляет очень быстрые, поколения # 0 коллекции очень дешевы.

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

Смежные вопросы