Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> реализация алгоритма 
:(
    Опции темы
boostcoder
Дата 9.11.2011, 09:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



всем бодрого утра.

итак. имеется протокол ввода-вывода. пакет состоит из заголовка фиксированного размера в котором содержится всякая инфа, размер тела данных, и, собственно, тело.
в данный момент, чтение пакета происходит следующим образом: 1)читается заголовок, 2)из заголовка узнается объем тела, 3)читается тело.

тут, мне не нравится то, что для чтения одного пакета приходится выполнять две операции чтения. а это довольно длинная цепь вызовов, в придачу, завершающаяся системным вызовом.

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

при такой реализации мы получаем следующую информацию основанную на позициях итераторов:
1. позиция итератора чтения нам говорит о том, сколько данных было прочтено.
2. дистанция от итератора чтения до итератора записи = объем доступных в буфере данных.
3. дистанция от итератора записи до итератора чтения = пространство доступное для записи.

при создании операции асинхронного чтения, в качестве буфера передаем итератор записи, а объем определяем согласно пункту 3 предыдущего параграфа.
операция асинхронного чтения читает из сокета все доступные данные, но не более чем было запрошено.

в общем, это изложение мысли как есть, без проработки и связи. наверняка что-то не учел, не додумал..


собственно тема создана для того, чтоб выслушать мнение форумчан, и, возможно, выявить "узкие" места и недочеты.


всем спасибо.

Это сообщение отредактировал(а) boostcoder - 9.11.2011, 11:10
PM WWW   Вверх
bsa
Дата 9.11.2011, 10:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Ты уверен, что именно на чтение сокета убивается большая часть ресурсов процессора? Что-то мне подсказывает, что это не так... Скажи, а как именно данные оправляются? Есть подозрение, что отправляются они так же, как принимаются - сначала заголовок, а затем тело. Таким образом, есть у меня подозрение, что сначала выполнится операция чтения, возвращающая только заголовок, а уже затем чтение тела, так как придут в разных пакетах... Или я не прав (в сетях я не большой гуру)?
PM   Вверх
boostcoder
Дата 9.11.2011, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(bsa @  9.11.2011,  10:33 Найти цитируемый пост)
Ты уверен, что именно на чтение сокета убивается большая часть ресурсов процессора?

я бы не сказал что бОльшая..но порядочно. около 12 процентов.

Цитата(bsa @  9.11.2011,  10:33 Найти цитируемый пост)
сначала заголовок, а затем тело

не-не-не. отправка данных происходит за раз. с этим все нормально.

PM WWW   Вверх
mabrarov
Дата 9.11.2011, 11:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Утра бодрого и Вам, boostcoder.
asio::buffered_read_stream и
asio::buffered_write_stream и, наконец, 
asio::buffered_stream.

Это позволит сэкономить на обращениях к сокету. В принципе, Вы этого и хотели. Но я предпочитаю иной вариант, потому что каждый async-запрос к buffered_stream все равно выливается в копии handler и пр. мелочевку. Для примера возьму чтение (алгоритм для записи выводим как-то по аналогии).

Итак, берем кольцевой буфер (ma::cyclic_buffer), размер которого >= максимальный размер сообщения (в идеале >>>). В каждой итерации пытаемся читать из сокета - (async_)read_some - столько, сколько есть/осталось свободного места в буфере. Отдельным объектом (class message_parser) парсим то, что считалось в буфер. При этом, на выходе message_parser::parse_some м/б [0..n] сообщений. message_parser есть КА и хранит текущее состояние парсинга с тем, чтобы при каждом последующем вызове не парсить всю последовательность с начала. Вообще в message_parser::parse_some каждый раз передаются только новые (вновь поступившие) данные (buffer_sequence или, точнее, ma::cyclic_buffer::const_buffers_type).

Если message_parser::parse_some (худший случай) длительный, то его можно проводить параллельно, но это уже больше похоже на извращение. Чтение (async_read_some) всегда выполняется в фоне. Т.е. сначала начинаем следующую итерацию чтения (start_async_read_some), а уже потом вызываем message_parser::parse_some. Поэтому, если уж message_parser::parse_some длительный, то эффективнее будет async_read_some + asio::null_buffers + неблокирующий режим. Такой режим, между прочим, считается последним спасением при высоких нагрузках и IOCP - видел англоязычную запись в каком-то блоге, посвященном IOCP и высоким нагрузкам (до сих пор найти не могу - может кто подскажет?).

Еще такой момент - все, что прошло через message_parser::parse_some, может 
1. считаться "свободным", т.е. освобождается в кольцевом буфере под запись новых данных (ma::cyclic_buffer::commit)
или 
2. message_parser::parse_some может дополнительно сообщать, сколько байт от начала переданной ему buffer_sequence можно считать "проглоченными парсером", т.е. "свободными".

Если не устраивает кольцевой буфер, то можно взять обычный. Но тогда в случае [2] (см. выше) нужно предусмотреть shift - сдвиг распарсенных, но не извлеченных из буфера данных в начало буфера с тем, чтобы обеспечить ненулевой свободный остаток в конце буфера. Можно делать сдвиг не всегда, а только в тех случаях, когда "свободный остаток в конце буфера" < threshold (я так и делал когда-то).

Все вышеописанное есть тот же самый buffered_stream, но с выделением логики парсинга из логики чтения. "100-пудов" это всем было известно и без меня. Но захотелось заодно и обсудить.

P.S. ma::cyclic_buffer.

Это сообщение отредактировал(а) mabrarov - 9.11.2011, 11:20
PM MAIL WWW Skype   Вверх
newbee
Дата 9.11.2011, 11:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



ОП прочла по диагонали, по-моему ты слишком усложняешь. Скорее всего цпу забивает процесс разбора пакета, а не чтения из сокета. Но даже если так, можно сделать много проще, ведь скорость обмена данными у тебя очень велика. Читаешь из сокета большой (в идеале заведомо больший, чем возможная максимальная длина пакета*) кусок данных, натравливаешь на него парсер.  Опять читаешь буфер, продолжаешь парсить, и т.д. Процесс можно пустить в два потока: один парсит имеющийся буфер, другой читает следующий буфер. Если парсер будет сильно не успевать за читалкой, можно сделать пул парсеров.

*под пакетом я имею в виду твой фрейм поверх IP/UDP/TCP/etc.


--------------------
You're face to face
With man who sold the world
PM   Вверх
mabrarov
Дата 9.11.2011, 11:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(newbee @ 9.11.2011,  11:20)
ОП прочла по диагонали, по-моему ты слишком усложняешь. Скорее всего цпу забивает процесс разбора пакета, а не чтения из сокета. Но даже если так, можно сделать много проще, ведь скорость обмена данными у тебя очень велика. Читаешь из сокета большой (в идеале заведомо больший, чем возможная максимальная длина пакета*) кусок данных, натравливаешь на него парсер. ...

"Если что" (если я непонятно выразился), я имел в виду то же самое. У Вас получилось описать это проще smile

Это сообщение отредактировал(а) mabrarov - 9.11.2011, 11:29
PM MAIL WWW Skype   Вверх
newbee
Дата 9.11.2011, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



mabrarov, когда я начинала писать, твоего сообщения еще не было. Так что это не плагиат smile


--------------------
You're face to face
With man who sold the world
PM   Вверх
mabrarov
Дата 9.11.2011, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(newbee @ 9.11.2011,  11:29)
mabrarov, когда я начинала писать, твоего сообщения еще не было. Так что это не плагиат smile

Да какой уж тут плагиат. Не "алгоритм Дейкстры" же. Просто у меня получилось запутанно. Вдруг кого смутит.
PM MAIL WWW Skype   Вверх
baldina
Дата 9.11.2011, 11:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата(newbee @  9.11.2011,  11:20 Найти цитируемый пост)
Скорее всего цпу забивает процесс разбора пакета, а не чтения из сокета

те 12 процентов видимо из-за системного вызова, а не разбора заголовка.
тем не менее буферизация и параллельная работа с буфером мне кажется более удачной идеей чем прыжки с сокетами и итераторами
PM MAIL   Вверх
mabrarov
Дата 9.11.2011, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(baldina @ 9.11.2011,  11:40)
тем не менее буферизация и параллельная работа с буфером мне кажется более удачной идеей чем прыжки с сокетами и итераторами

То, что описал boostcoder, и еcть буферизация. Тот же самый asio::buffered_stream.
PM MAIL WWW Skype   Вверх
boostcoder
Дата 9.11.2011, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(newbee @  9.11.2011,  11:20 Найти цитируемый пост)
Читаешь из сокета большой (в идеале заведомо больший, чем возможная максимальная длина пакета*)

нельзя читать больше, чем доступно для чтения без блокировки. иначе есть риск того, что я не смогу обработать первый пришедший пакет из-за того, что мы попросили прочитать 200 пакетов.

Цитата(newbee @  9.11.2011,  11:20 Найти цитируемый пост)
Скорее всего цпу забивает процесс разбора пакета

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

Цитата(baldina @  9.11.2011,  11:40 Найти цитируемый пост)
те 12 процентов видимо из-за системного вызова

угу. и из-за всего предшествующего. т.е. байндеры, io_service, new/delete, и т.д.

про asio::buffered_stream никогда не читал. почему-то...

в общем, сейчас "переварю" мысли/идеи....
PM WWW   Вверх
mabrarov
Дата 9.11.2011, 12:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(boostcoder @ 9.11.2011,  12:07)
нельзя читать больше, чем доступно для чтения без блокировки. иначе есть риск того, что я не смогу обработать первый пришедший пакет из-за того, что мы попросили прочитать 200 пакетов.

У Вас async_read_some или async_read? async ли вообще? Потому что async-операции вполне позволяют Вам разбирать то, что уже пришло, параллельно чтению.

Это сообщение отредактировал(а) mabrarov - 9.11.2011, 12:27
PM MAIL WWW Skype   Вверх
boostcoder
Дата 9.11.2011, 12:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mabrarov @  9.11.2011,  12:24 Найти цитируемый пост)
У Вас async_read_some или async_read?

async_read()
дело в том, что разбирать я начинаю в хендлере. а хендлер вызовется только тогда, когда будет прочитано указанное кол-во байт. т.е. к примеру мы указываем прочитать 200 байт, а в сокете есть только 100. так вот эти 100 я не могу обработать, потому что не вызывается хендлер.

тут наверное правильней использовать async_read_some()... значит нужно менять архитектуру.

Добавлено @ 13:04
почитал я asio::buffered_stream(если можно это назвать чтением)... в доке, вообще нет никакого описания поведения или принципа работы. ни каким образом получает данные, ни кто такой Arg  smile 
полез в исходники.

Это сообщение отредактировал(а) boostcoder - 9.1.2012, 15:49
PM WWW   Вверх
bsa
Дата 9.11.2011, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(boostcoder @ 9.11.2011,  13:59)
почитал я asio::buffered_stream(если можно это назвать чтением)... в доке, вообще нет никакого описания поведения или принципа работы. ни каким образом получает данные, ни кто такой Arg  smile 
полез в исходники.

Я давно заметил, что Asio отличается особой полнотой и глубиной описания... Не то что всякие Qt...
PM   Вверх
mabrarov
Дата 9.11.2011, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(boostcoder @ 9.11.2011,  12:59)
почитал я asio::buffered_stream(если можно это назвать чтением)... в доке, вообще нет никакого описания поведения или принципа работы. ни каким образом получает данные, ни кто такой Arg  полез в исходники.

Вот именно эта часть вообще недокументированна. Вроде бы раньше это были служебные (внутренние для Asio) классы. Сам все хочу почитать их исходники, но никак не сделаю это последовательно и целиком.

Arg - это параметр для конструктора lower_layer. В случае, если lower_layer есть asio::ip::tcp::socket, то Arg - это asio::io_service&. Тут все аналогично asio::ssl::stream. Это вообще общая техника для оберток в Asio.

Добавлено @ 13:55
Цитата(bsa @ 9.11.2011,  13:23)
Я давно заметил, что Asio отличается особой полнотой и глубиной описания... Не то что всякие Qt...

Естественно. У Qt есть коммерческая версия + Trolltech/Nokia. Там есть кому писать и что платить "писателям". Ну напишете наконец Chris-у совместную "петицию" с указанием, что непонятно и где дописать/уточнить/поправить. В рассылке по Asio пока не было такого письма. В одной "российской" компании на Y мне (asio samples) сказали: "А чего там писать? И так все понятно - проще некуда".
И в Qt встречаются плохо документированные места. Попадалось использование !QObject raw pointer без объяснения, кто будет владеть ресурсом и кто будет его удалять/освобождать.

Добавлено @ 13:58
Цитата(boostcoder @ 9.11.2011,  12:59)
тут наверное правильней использовать async_read_some()... значит нужно менять архитектуру.

Можно попробовать asio::async_read + asio::transfer_at_least(минимальный размер пакета).
В той же компании Y не используют asio::async_xxx (мне так сказали - сам не проверял smile ) - только async_xxx_some. Видимо, они работают с таймаутами так же, как echo_server из asio samples - когда идет таймаут не на передачу n-го кол-ва данных, а таймаут на "активность". Т.е. если принят всего один байт, но он уложился в таймаут, то все ok - продолжаем держать соединение.

Это сообщение отредактировал(а) mabrarov - 9.11.2011, 14:10
PM MAIL WWW Skype   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0580 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.