возможно, лучше начать с платформо-специфических имплементаций того же asio, ибо здесь уже нужно сравнивать конкретные реализации на epoll, kqueue, etc.:
IMHO broken by design, потому что требует отдельного потока под обработку событий. То есть, для того, чтобы заюзать в своем однопоточном приложении boost::asio, придется запилить еще один тред, который не будет ничего полезного делать, а просто обрабатывать события. И это при том, что сама аснхронность в boost::asio AFAIK сделана на потоках (кроме винды, которая единственная умеет AS I/O нативно).
У меня вопросов ещё есть(сразу скажу, что я до этого момента бустом не пользовался вообще).
Каков принцип организации asio? Один поток рассказывает задачи по worker'ам или используется select?
Он же ведь однопоточный, не?
А как сейчас обстоят дела с поддержкой c++11 boost'ом? Например chrono для таймеров можно использовать или лучше boost'овые плюшки управления временем?
Я проблем не испытывал. Но мешать сущности не рекомендую, то есть если используешь std::thread, то используй его во всем проекте, без примесей boost::thread'а.
Инфа с их документации, может и не последней версии.
IMHO broken by design, потому что требует отдельного потока под обработку событий.
не требует
Значит я что-то не знаю - расскажи мне пожалуйста. Вот у меня есть приложение, у которого есть один единственный поток с его event loop. В винде это один из: 1. GetMessage()/DispatchMessage(), 2. WaitForMultipleObjects()/MsgWaitForMultipleObjects(). Обобщенно - MsgWaitForMultipleObjects. В линуксе это, к примеру, event loop Qt (QEventLoop, насколько я понимаю). Как использовать boost::asio, не создавая новых тредов?
Кстати std::thread и boost::thread в одно время эпично различались. В boost деструктор незадетаченого потока внезапно вызывал потенциально бесконечный join(), а в уже вышедшем C++11 за это написано бить по рукам посредством std::terminate(), а join() объявлен мудацким.
А потом, после обновления буста, код моего китайского коллеги наконец-то начал падать, а не тупить.
В винде это один из: 1. GetMessage()/DispatchMessage(), 2. WaitForMultipleObjects()/MsgWaitForMultipleObjects(). Обобщенно - MsgWaitForMultipleObjects. В линуксе это, к примеру, event loop Qt (QEventLoop, насколько я понимаю). Как использовать boost::asio, не создавая новых тредов?
У тебя каша в голове. Ты путаешь низкоуровневые системные функции с обертками (QEventLoop). В линуксе это, внезапно, poll/epoll/select.
У тебя каша в голове. Ты путаешь низкоуровневые системные функции с обертками (QEventLoop). В линуксе это, внезапно, poll/epoll/select.
Да нет у меня каши. Под виндой - или Qt или, как всегда, личный говнофреймворк (который любой большой софт уже написал лично для себя 10+ лет назад). Внизу - всегда указанные вызовы WinAPI. В линуксе - тот же poll/epoll/select.
Я хочу знать, как в, к примеру, Qt-приложении, объединить в одном потоке io_service::run() и QEventLoop.
Прочитал. И? И как мне он поможет? Предположим, у меня есть абстрактное приложение, в котором уже есть следующий event loop:
Простой случай - есть набор fd, которые слушаются через epoll(). Как добавить работу с io_service без тупой траты проца на вызовы io_service::poll()? Т.е. мне нужно добавить в io_service свои fd и слушать также их тем же run(). Как?
Более сложный случай. Есть QEventLoop, в котором глубоко внутри закопаны fd с их обработчиками и он их не отдаст. Соответственно мне теперь нужно выковырять из io_service его fd и досунуть их в QEventLoop (QEventLoop это хотя бы умеет). Что делать?
Если такая задача возникает, то у тебя два event-loop'а обрабатывают разные события. Например, QEventLoop отвечает за гуй, а io_service::run отвечает за сеть. Очевидно, работать они будут в отдельных потоках.
Если такая задача возникает, то у тебя два event-loop'а обрабатывают разные события. Например, QEventLoop отвечает за гуй, а io_service::run отвечает за сеть. Очевидно, работать они будут в отдельных потоках.
Да эта задача возникает чуть более, чем всегда! Нет, ну что, я какой-то нереальный пример выдумал? И вот тут boost и показывает, что для использования asio нужно беспричинно стать раком. Вместо того, чтобы сделать абстрактный интерфейс event loop'а и его эталонную реализацию, они всунули event loop в ни в чем не виновное asio.
Это говно, я просил именно код бенчмарка на котором они это получили - это жалкая муть. Что там эти 2строчки - они мне не интересны. Такого я нагинерить могу и сам из urandoma"а.
Бенчмарков я вообще не нагуглил - только мистические записи. На чем получены, как получены - никакой инфы. Очередное балабольсво.
((1.6×10^9)×0.007)÷10^4 - это char2string - это даже на частоте 1.6 1к+ тактов на каст. Какой жопой можно добится овер1к тактов на char2string - это выше моего понимания. Твои цифры говно. Сейчас померил uint2string(по их методике - sprintf()) - 200тактов, хотя по их цифрам должно получится 3к, приэтом заметь я взял 1.6 - это самая низкая ТТ для х86. Реально их цифры говорят о 5-6к тактов.
200 тактов у меня - это 44нс, 10к итераций - это 440к нс, либо 440 мкс, либо 0.44 мс, когда как у пацанов 18 - это 32раза разница. Ещё одно подтврждение того, что втои цифры говно. И только идиоты не пишут в тестах минимум ТТ, а нормально и модельку камня, чтобы я мог оценить.
Вывод - рекламная псевдоинфа для нешарющих в теме рядовых анскильных прикладных балаболов.
Да и это касты, а не форматированный вывод - это совершенно разные вещи. То, что некоторые ущербаны кастуют sprintf'м - это не делает его кастом. И тотолько тотальный ущербан зпилит касты, которые будут медленее sprintf'а и будет с ним соревноваться. А уж гордится 3к тактов на каст - ну это идиотизм.
О5 ты несёшь херню, как жешь вы меня одалели - это не код. Код - это полный бенчмарк, которого я не в сорцах буста, ни в гугле не нашел. Ёперный театр: sprintf( (char*)buffer, conv, _in) - код кодов. Я не собираюсь ваять что-то на говнобусте, чтобы ещё раз убедиться в том, что эти цифры - говно. Поэтому норм пацаны и выкладывают код.
Я уже тебе объяснил почему твой линк - бесполезное говно, которое ну никак не имеет отношения к реальному миру. q4 2012 время релиза 1.48 - это время актуальности минимум нехалема, а уж коре2 точно - это средняя тт 2.6+ггц - т.е. ~5к тактов на каст. Это тотальный гон и бред.
Похоже отвечать за вменяемость цифр в твоих пруфцах ты не хочешь, да и не можешь, но нахрена ты тогда начинаешь это поситить? Ещё раз тебе повторю - у меня sprintf() работает в 35раз быстрее, чем в твоём пруфце. В глибц его не меняли уже 10лет, х86 тоже не имели таких явных прогрессов. С чего разница в 35раз? Ответ один - /dev/urandom.
О5 ты несёшь херню, как жешь вы меня одалели - это не код. Код - это полный бенчмарк, которого я не в сорцах буста, ни в гугле не нашел. Ёперный театр: sprintf( (char*)buffer, conv, _in) - код кодов. Я не собираюсь ваять что-то на говнобусте, чтобы ещё раз убедиться в том, что эти цифры - говно. Поэтому норм пацаны и выкладывают код.
Я уже тебе объяснил почему твой линк - бесполезное говно, которое ну никак не имеет отношения к реальному миру. q4 2012 время релиза 1.48 - это время актуальности минимум нехалема, а уж коре2 точно - это средняя тт 2.6+ггц - т.е. ~5к тактов на каст. Это тотальный гон и бред.
Похоже отвечать за вменяемость цифр в твоих пруфцах ты не хочешь, да и не можешь, но нахрена ты тогда начинаешь это поситить? Ещё раз тебе повторю - у меня sprintf() работает в 35раз быстрее, чем в твоём пруфце. В глибц его не меняли уже 10лет, х86 тоже не имели таких явных прогрессов. С чего разница в 35раз? Ответ один - /dev/urandom.
Нуу вставание раком и состоит как раз в необходимости создания выделеного потока и rpc-like интерфейса общения с ним.
И как ты себе представляешь этот «абстрактный интерфейс»?
ОС-независимый - надо подумать, но IMHO реализуем с приемлемой степенью кривизны.
Пример из Qt: QAbstractEventDispatcher::registerSocketNotifier() позволяет добавить в их event loop экземпляр QSocketNotifier. Вот QSocketNotifier и есть пример кроссплатформенного объекта - связки «дескриптор+флаги+обработчик события». Немного кривой, но всё же.
Абстрактный event loop - позволяет добавлять и удалять такие связки, а также предоставляет методы типа run(),processPendingEvents(), etc.
Нуу вставание раком и состоит как раз в необходимости создания выделеного потока и rpc-like интерфейса общения с ним.
Зачем rpc-like? В boost::asio есть функция post в которую можно передать всё что угодно, в том числе лямбду. При этом переданное у тебя гарантированно выполнится в треде event-loop'а. В этом и есть сила буста, что не надо заморачиваться на счет интерфейсов и всяких сложных иерархий с наследованиями. Гибкости больше чем в qt.
Пример из Qt: QAbstractEventDispatcher::registerSocketNotifier() позволяет добавить в их event loop экземпляр QSocketNotifier.
Это чтобы вместо дефолтового диспатчера использовать непойми что? А в чем абстракция и профит и как это поможет связать обработчики, созданные для разнородных event-loop'ов?
а также предоставляет методы типа run(),processPendingEvents(),
Зачем rpc-like? В boost::asio есть функция post в которую можно передать всё что угодно, в том числе лямбду. При этом переданное у тебя гарантированно выполнится в треде event-loop'а. В этом и есть сила буста, что не надо заморачиваться на счет интерфейсов и всяких сложных иерархий с наследованиями. Гибкости больше чем в qt.
Я знаю и пользуюсь. Вот этот post, на котором и приходится делать общение, я и называю rpc-like. Потому что ответ назад отсутствует - считай половина RPC.
Это чтобы вместо дефолтового диспатчера использовать непойми что? А в чем абстракция и профит и как это поможет связать обработчики, созданные для разнородных event-loop'ов?
Профит в том, что можно будет в тот же QEventLoop добавить все события от boost::asio и избавиться от лишнего потока, который иначе используется только для форвардинга запросов (только увеличивая latency этих запросов).
Если же в приложении изначально юзается простой epoll() вместо QEventLoop, то альтернативно можно будет в эталонную реализацию абстрактного event loop докинуть свои обработчики, и, таким образом, заменить велосипедный epoll() на этот event loop.
Можно подумать в boost::asio этого нет.
А толку, если нельзя добавить свои обработчики? Это и остается asio-only решением, в которое нельзя встроить ничего своего, равно как и наоборот.
Потому что ответ назад отсутствует - считай половина RPC.
Зачем он там нужен, если туда завернуть можно всё что угодно? В чем проблема завернуть аналогичный «post» из qt или что ты там используешь?
А толку, если нельзя добавить свои обработчики? Это и остается asio-only решением, в которое нельзя встроить ничего своего, равно как и наоборот.
У нас разные понимания своих разработчик. В моем понимании свой это произвольный кусок кода, в терминах Qt так не получается и приходится танцевать с бубном вокруг наследований и конкретных сигнатур. В моей практике в серьезных больших приложениях qeventloop использовался _только_ для гуя, всё остальное делалось на boost::asio из-за больше гибкости.
В чем проблема завернуть аналогичный «post» из qt или что ты там используешь?
Я расскажу. У меня под носом есть проект, наработки которого приходится использовать. Так вот, там есть 2 потока - гуй и worker. И общение между ними происходит через тот же перепихон замыканиями. Так вот - одна из причин, почему оно глючит как капец - в том, что код, вызвавший местный аналог post(), не ждет ответа, а возвращается к своим делам. А потом выясняется, что в момент обработки этого замыкания в другом треде контекст уже изменился и объектов, над которыми нужно проводить манипуляции, уже нет. Как всегда, в каком-то месте не хватает проверки и всё падает. Падает потому что не проверки? - Нет, из-за дебильного дизайна, который такое допускает. Поддерживать такой код - тот еще гемор (учитывать все возможные случаи изменения контекста и правильно на них реагировать). Надо просто избегать таких способов взаимодействия.
У нас разные понимания своих разработчик. В моем понимании свой это произвольный кусок кода, в терминах Qt так не получается и приходится танцевать с бубном вокруг наследований и конкретных сигнатур.
Не понял тебя.
В моей практике в серьезных больших приложениях qeventloop использовался _только_ для гуя, всё остальное делалось на boost::asio из-за больше гибкости.
Вообще QEventLoop тут только для примера. Я тоже предпочел бы не использовать его как цикл для негуя. Но я хочу не плодить потоки без причин. «без причин» - это если поток в своей жизни не делает ничего полезного. Т.е. не блокируется на I/O или занимается вычислениями. Иначе это гемор с IPC и пустая трата проца на переключения контекста (да, мне приходится работать с не самым мощным железом и с требованиями к производительности).
Возможность встроить QEventLoop/epoll() в boost::asio::io_service или наоборот сильно упростила бы дизайн и улучшила производительность.
Братюнь, извини, но у тебя вопросы а-ля «я надел на голову портки, посоветуйте линзы для очков чтобы лучше видеть», ну и в целом они туповаты и твоя компетенция оставляет желать лучшего, так что откланиваюсь.
Это не пруфцы. Я уже писал выше - мои цифры в 30раз отличается от твоего говна. Это тотальное говно. Ты сам говорил и я выше тоже говорил - только обсосоки юзают sprintf() как каст, ибо это не каст, а фортатированный вывод.
Эти цифры говно, а буст тоже говно. Ещё раз повторю 6к тактов на каст.