И теперь шедулер должен знать, как с каким ресурсом работать, что вроде как очевидно. Для простейших случаев всё в порядке. Для сложных — пилить и пилить.
Получается так — async/await это подсказки шедулеру, что в каком порядке вызывать. Как видно, в С++ нужны ровно те же подсказки.
Итого — ты изобрел аналог async/await, но работающий только для простейших случаев.
Здравствуйте, Ikemefula, Вы писали:
I>Теперь вопрос — что если разделяемое состояние не связано со стримом или кроме стрима есть еще какое то разделяемое состояние ?
I>Это значит, что надо вводить еще одну конструкцию
I>
I>И теперь шедулер должен знать, как с каким ресурсом работать, что вроде как очевидно. Для простейших случаев всё в порядке. Для сложных — пилить и пилить.
Не, даже если мы захотим переделать несколько синхронных операций на асинхронные внутри одной функции, то всё равно они все будут реализованы через одну сопроцедуру (которая задаётся скобками async_code) и соответственно друг относительно друга будут выполняться последовательно. Так что никаких проблем.
Вот если бы мы захотели именно параллельное исполнение нескольких асинхронных операций (запускаемых изнутри operation), то это уже да, действительно потребует переписывания нашей функции...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, artelk, Вы писали:
A>>На сколько удалось разобрать (давно с++ не трогал), в качестве "оповещения о завершении" из других потоков у тебя делается добавление задания в main_tasks, которое будет выполняться в main потоке. "Задание" заключается в том, чтобы "перескочить" в место, откуда делался await, так?
EP>Да, абсолютно верно. В данном примере await помогает заменить код вида:
<...> EP>Причём это простейший пример, если добавляются циклы, условия — без await/yield/coroutine/etc, код становится запутанным и утомительным.
Хорошо. А что если захочется продолжиться в тред пуле, как быть?
Представь, нам нужно:
1. Скачать что-то по сети
2. Провести над содержимым некие вычисления
3. Записать что-то в файл
4. Вернуть что-то
Здравствуйте, alex_public, Вы писали:
_>Не, даже если мы захотим переделать несколько синхронных операций на асинхронные внутри одной функции, то всё равно они все будут реализованы через одну сопроцедуру (которая задаётся скобками async_code) и соответственно друг относительно друга будут выполняться последовательно. Так что никаких проблем.
Смотри внимательно — у тебя все хорошо работает, если read асинхронный. А теперь фокус — асинхронным становится еще и write.
Как шедулер узнает, что ему надо подождать с переключением очередной короутины ?
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Кстати это верно для любого простого парсинга. А для сложного, Spitit неочень подойдет. _>Пока что я вижу что это не верно даже для такого. )))
G>>Присылай exe, проверим.
_>http://files.rsdn.ru/98162/rsdn.zip — прошу. )
_>И так результаты: _>C#: TotalMilliseconds : 3888,1258 _>C++: TotalMilliseconds : 280,8465
_>О, я даже немного ошибся в своём прогнозе... Не в 10 раз тормознее .net код, а в 14!
Я сделал версию на C#, которая отрабатывает за 600мс, когда твоя работает около 400мс.
НО. Чтение 100мб файла с диска без кеша идет 8сек. В этих условиях пидарасить такты вообще бессмысленно.
http://files.rsdn.ru/67312/ConsoleApplication5.exe
G>>Конкретно тормозит маршалинг каждого вызова через UI. Это для простых фоновых операций подойдет, а для сложных — будет тормозить. _>Кто такие "сложные" фоновые операции? Если ты снова про серверный вариант, то там никто и не собирается использовать цикл сообщений — там рулит библиотека IO.
Boost:asio? Так она тоже все в один поток маршалит.
G>>Что касается масштабирования, то все просто — все корутины работают в одном потоке, по факту получится очередь с одним читателем, даже если у тебя в системе десятки ядер. _>Ну так и запускаем много потоков и в каждом свой набор сопроцедур. Собственно Boost.Asio именно на такой сценарий и заточен (в смысле без сопроцедур, а просто с коллбэками)
Но это неоптимальный сценарий и более сложный для реализации.
Простите великодушно, что снова влезаю в спор столь учёных мужей.
Просто я снова наткнулся на одном форуме на свежее обсуждение многопоточного сервера на C++. И снова там матёрые плюсисты (сужу банально по количеству их сообщений на форуме) предлагают на каждое соединение создавать по потоку. То есть 50 соединений с клиентами — 50 потоков. Имхо, ни один дотнетчик-миддл не мог бы сморозить такую глупость...
Я обеими руками за нативный код. Однако в очередной раз вынужден сказать: всё, что в этой теме приводят в пример alex_public, Evgeny.Panasyuk и прочие, — это удел гуру C++. Чтобы дойти до Boost.Asio, корутин и прочего — нужен многолетний опыт.
Между тем, в дотнете уже джуниоры вовсю юзают TPL и async/await.
Моя мысля: достоинство дотнета в том, что он активно рекламируется и продвигается, выпускается масса новой литературы, где освещены новейшие фичи. Поэтому даже новички вовсю пишут асинхронный код.
Серьёзнейший недостаток C++ в том, что новые возможности и библиотеки рекламируются очень и очень мало. Более того, сами же матёрые плюсисты, в ответ на вопрос начинающих, с чего начать учиться, чаще всего предлагают старую замшелую литературу 90-х годов. Не, так-то те книги хорошие. Вот только начав с них, до корутин/буста/etc новоиспечённый плюсист дойдёт ой как не скоро.
P.S. продолжайте в том же духе: почерпнул очень много полезного по крутым фичам цпп.
Здравствуйте, Ikemefula, Вы писали:
I>Смотри внимательно — у тебя все хорошо работает, если read асинхронный. А теперь фокус — асинхронным становится еще и write.
Ну и никаких проблем. Исполнение функции то прекращается внутри async_read и возвращается только после прочтения данных. Так что async_write будет запущен только после этого, и там дальше по той же схеме. В общем если мы говорим о последовательных асинхронных запусках, то их можно делать сколько угодно и без всякого переписывания нашей функции.
I>Как шедулер узнает, что ему надо подождать с переключением очередной короутины ?
Здравствуйте, koodeer, Вы писали:
K>Чтобы дойти до Boost.Asio, корутин и прочего — нужен многолетний опыт.
Никогда не занимался профессиональной разработкой client/server — не было таких задач. Изучал/игрался только ради интереса.
В Boost.Asio корутины уже встроены, причём и stackless и stackful.
Более того, что-то производное от Asio должно войти в стандартную библиотеку. Плюс по корутинам сейчас есть два proposal'а, то есть вероятно они войдут в C++17.
K>Серьёзнейший недостаток C++ в том, что новые возможности и библиотеки рекламируются очень и очень мало. Более того, сами же матёрые плюсисты, в ответ на вопрос начинающих, с чего начать учиться, чаще всего предлагают старую замшелую литературу 90-х годов. Не, так-то те книги хорошие.
1. По C++ есть много плохих книг, которые учат стилю который не свойственен языку. Новичку выбрать правильную книгу без постороннего совета действительно трудно.
2. То что было в 90-х, мало применимо сегодня. Учить C++ нужно по современным книгам. Например книга Страуструпа — Programming -- Principles and Practice Using C++ — (Причём она нацелена не просто на новичков в C++, а на новичков в программирование вообще. Надеюсь он её обновит до C++11/14).
K>Вот только начав с них, до корутин/буста/etc новоиспечённый плюсист дойдёт ой как не скоро.
По библиотекам Boost есть различные overview, слайды, видео-презентации, и т.п. Также Boost упоминается во многих книгах, например у Страуструпа, Александреску, Саттера, Майерса.
Но в целом согласен, какой-то общепринятой книги, которая делает high-level обзор распространённых библиотек (Boost, Poco, QT, Cinder, openFrameworks, etc) — я не встречал. И да — заблудится новичку без посторонней помощи очень легко, поэтому нужно постоянно задавать вопросы (например тут, или на stackoverflow).
Здравствуйте, gandjustas, Вы писали:
G>Я сделал версию на C#, которая отрабатывает за 600мс, когда твоя работает около 400мс.
Агааа, а теперь подведём итоги теста. Для написания более менее производительного решения ты не использовал для парсинга ни одной функции из стандартной библиотеки .net! Хотя дискуссия собственно и началась с твоего высказывания о её крутизне. Вместо этого ты написал сотню строк рукопашного нерасширяемого unsafe кода, который при этом оказался всё равно в 2 раза (см ниже) медленнее 5 строк на C++.
G>НО. Чтение 100мб файла с диска без кеша идет 8сек. В этих условиях пидарасить такты вообще бессмысленно.
Ну так и примерчик был максимально простой. Стоит чуть усложнить формат файла и время парсинга станет уже принципиальным.
Это если говорить про не мобильные устройства. А в случае мобильных имеет значение даже и этот пример, потому как получается разница между 0.3 и 3 секундами существенной загрузки процессора. И вот как раз такой "ява подход", что пофиг на оптимальность кода, если всё равно данные ждать надо, и приводит к просадкам батареи...
G>http://files.rsdn.ru/67312/ConsoleApplication5.exe
Кстати, этот exe ещё и не запустился у меня — вот она бинарная переносимость .net'a во всей красе... ))) Пришлось выдрать код и скомпилировать самому. В итоге действительно получилось всего в 2 раза медленнее C++ варианта.
G>Boost:asio? Так она тоже все в один поток маршалит.
Вообще то там всё зависит от выбранной реализации. Для разных платформ там всё разное. Т.е. да, оно подразумевает один поток, но я бы не стал называть какой-нибудь epoll маршалингом. )))
G>Но это неоптимальный сценарий и более сложный для реализации.
Ну т.к. он уже реализован, то как бы проблем нет. Ну и насчёт быстродействия я бы опять же не рекомендовал соревноваться с Boost'ом...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Смотри внимательно — у тебя все хорошо работает, если read асинхронный. А теперь фокус — асинхронным становится еще и write.
_>Ну и никаких проблем. Исполнение функции то прекращается внутри async_read и возвращается только после прочтения данных. Так что async_write будет запущен только после этого, и там дальше по той же схеме. В общем если мы говорим о последовательных асинхронных запусках, то их можно делать сколько угодно и без всякого переписывания нашей функции.
У меня за все время ни разу не случались исключительно последовательне запросы в асинхронщине Пудозреваю, это именно та причина, из за которой я сомневаюсь в возможностях С++
I>>Как шедулер узнает, что ему надо подождать с переключением очередной короутины ?
_>Эээ кому ждать, где, зачем?
Да очень прость — между стартом и концом асинхронного write появляется еще один асинхронный запрос которй затрагивает инвариант. всё, приехали.
Здравствуйте, koodeer, Вы писали:
K>Просто я снова наткнулся на одном форуме на свежее обсуждение многопоточного сервера на C++. И снова там матёрые плюсисты (сужу банально по количеству их сообщений на форуме) предлагают на каждое соединение создавать по потоку. То есть 50 соединений с клиентами — 50 потоков. Имхо, ни один дотнетчик-миддл не мог бы сморозить такую глупость...
Нуу при определённых условиях (на количество одновременных подключений) это тоже может быть самым оптимальным решением... )))
K>Я обеими руками за нативный код. Однако в очередной раз вынужден сказать: всё, что в этой теме приводят в пример alex_public, Evgeny.Panasyuk и прочие, — это удел гуру C++. Чтобы дойти до Boost.Asio, корутин и прочего — нужен многолетний опыт. K>Между тем, в дотнете уже джуниоры вовсю юзают TPL и async/await.
Согласен, но с одной поправкой. Всё же Boost уже явно стал стандартом де факто, про который знает (но не значит что использует) наверное каждый C++'ник.
K>Моя мысля: достоинство дотнета в том, что он активно рекламируется и продвигается, выпускается масса новой литературы, где освещены новейшие фичи. Поэтому даже новички вовсю пишут асинхронный код.
Да, у .net'a и java есть своя ниша, в которой они однозначно лучшие.
K>Серьёзнейший недостаток C++ в том, что новые возможности и библиотеки рекламируются очень и очень мало. Более того, сами же матёрые плюсисты, в ответ на вопрос начинающих, с чего начать учиться, чаще всего предлагают старую замшелую литературу 90-х годов. Не, так-то те книги хорошие. Вот только начав с них, до корутин/буста/etc новоиспечённый плюсист дойдёт ой как не скоро.
В этом смысле D как получше будет для новичков. )))
Здравствуйте, Ikemefula, Вы писали:
I>У меня за все время ни разу не случались исключительно последовательне запросы в асинхронщине Пудозреваю, это именно та причина, из за которой я сомневаюсь в возможностях С++
Так твой пример же как раз чётко последовательный. В начале read, а потом write. Его нельзя переделать в параллельный даже если очень захочется. )))
I>Да очень прость — между стартом и концом асинхронного write появляется еще один асинхронный запрос которй затрагивает инвариант. всё, приехали.
Откуда он появляется то? Или ты снова про кривой асинхронный внешний код? Ты имеешь привычку запускать параллельные асинхронные операции модифицирующие одни и те же данные? )
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Я сделал версию на C#, которая отрабатывает за 600мс, когда твоя работает около 400мс.
_>Агааа, а теперь подведём итоги теста. Для написания более менее производительного решения ты не использовал для парсинга ни одной функции из стандартной библиотеки .net! Хотя дискуссия собственно и началась с твоего высказывания о её крутизне. Вместо этого ты написал сотню строк рукопашного нерасширяемого unsafe кода, который при этом оказался всё равно в 2 раза (см ниже) медленнее 5 строк на C++.
Это чтобы семантика соответствовала.
Какой смысл мерить время работы функции int.Parse, которая учитывает локальные настройки с рукопашным парсером?
Это ведь не реальная задача, а .net на реальные ориентирован.
G>>НО. Чтение 100мб файла с диска без кеша идет 8сек. В этих условиях пидарасить такты вообще бессмысленно. _>Ну так и примерчик был максимально простой. Стоит чуть усложнить формат файла и время парсинга станет уже принципиальным.
Но тогда и сложность решения будет другая. Ты ведь как обычно придумал пример, который не является даже близко похожим на реальную задачу.
Лучше покажи парсеры json и xml.
_>Это если говорить про не мобильные устройства. А в случае мобильных имеет значение даже и этот пример, потому как получается разница между 0.3 и 3 секундами существенной загрузки процессора. И вот как раз такой "ява подход", что пофиг на оптимальность кода, если всё равно данные ждать надо, и приводит к просадкам батареи...
да-да. парсить 100мб чисел на мобильном устройстве — очень актуально.
Можешь привести хоть одну реальную задачу? А то C++ получается силен только в искусственных примерах.
G>>Boost:asio? Так она тоже все в один поток маршалит.
_>Вообще то там всё зависит от выбранной реализации. Для разных платформ там всё разное. Т.е. да, оно подразумевает один поток, но я бы не стал называть какой-нибудь epoll маршалингом. )))
Нет, в документации черным по английскому написано что в один поток.
G>>Но это неоптимальный сценарий и более сложный для реализации. _>Ну т.к. он уже реализован, то как бы проблем нет.
Что реализовано? Грамотное распределение корутин по потокам? Я такого не увидел.
_>Ну и насчёт быстродействия я бы опять же не рекомендовал соревноваться с Boost'ом...
Учитывая что все в один поток маршалит — тормозить будет при масштабировании.
Здравствуйте, gandjustas, Вы писали:
G>Это чтобы семантика соответствовала.
Ну т.е. в самой библиотеки .net нет ничего с нужной семантикой... )
G>Какой смысл мерить время работы функции int.Parse, которая учитывает локальные настройки с рукопашным парсером?
Потому что тут мы сравниваем библиотеки, а не языки.
G>Но тогда и сложность решения будет другая. Ты ведь как обычно придумал пример, который не является даже близко похожим на реальную задачу. G>Лучше покажи парсеры json и xml.
Ха, вообще говоря то, чем мы сейчас тут с тобой развлекались — это было по сути написание парсера csv формата (собственно если ограничиться числами, то это в точности он и был). А csv — это один из самых популярных форматов для данных. Экспорт/импорт в него есть и в Офисе и во всех база данных (и там как раз бывают не только мегабайтные, но и гигабайтные файлы) и ещё много где. Так что может это ты у нас не в курсе реальных задач? )))
Кстати, масштаб потребности можно легко увидеть введя в гугле например "csv .net" — т.к. в самой стандартной библиотеке решения нет, то инет переполнен вариантами. Ну а с помощью Boost'a полноценный csv парсер пишется в 3 строки, причём он ещё будет намного быстрее всех этих сторонних .net библиотек.
G>да-да. парсить 100мб чисел на мобильном устройстве — очень актуально.
Да какая разница какой объём. Даже если 100Кб, он всё равно будет тратить в 10 раз больше процессорного времени. Соответственно при постоянном пользование таким кривым софтом, время жизни от аккумулятора заметно уменьшается. Представляю сколько бы жили смартфоны, если например все браузерные движки были написаны в стиле java/.net...
G>Нет, в документации черным по английскому написано что в один поток.
Ну так я и говорю что в одном потоке, но я бы не стал называть epoll маршалингом. )))
G>Что реализовано? Грамотное распределение корутин по потокам? Я такого не увидел.
Boost.Asio вообще не заточен под сопроцедуры. Там основной интерфейс на функциях обратного вызова. Что правда отлично подходит для записи через сопроцедуры типа бустовских.
Здравствуйте, alex_public, Вы писали:
I>>У меня за все время ни разу не случались исключительно последовательне запросы в асинхронщине Пудозреваю, это именно та причина, из за которой я сомневаюсь в возможностях С++
_>Так твой пример же как раз чётко последовательный. В начале read, а потом write. Его нельзя переделать в параллельный даже если очень захочется. )))
Я могу запустить сколько угодно таких операций. Собственно так большей частью и происходит.
I>>Да очень прость — между стартом и концом асинхронного write появляется еще один асинхронный запрос которй затрагивает инвариант. всё, приехали.
_>Откуда он появляется то? Или ты снова про кривой асинхронный внешний код? Ты имеешь привычку запускать параллельные асинхронные операции модифицирующие одни и те же данные? )
Пока что не придумали хорошего способа поместить всю базу данных в локальную переменную со всеми таблицами, колонками и строчками.
Здравствуйте, gandjustas, Вы писали:
_>>О, я даже немного ошибся в своём прогнозе... Не в 10 раз тормознее .net код, а в 14! G>Я сделал версию на C#, которая отрабатывает за 600мс, когда твоя работает около 400мс. G>НО. Чтение 100мб файла с диска без кеша идет 8сек. В этих условиях пидарасить такты вообще бессмысленно.
Здравствуйте, alex_public, Вы писали:
_>И так результаты: _>C#: TotalMilliseconds : 3888,1258 _>C++: TotalMilliseconds : 280,8465
_>О, я даже немного ошибся в своём прогнозе... Не в 10 раз тормознее .net код, а в 14!
Ты сравнил хрен с пальцем — ленивый процессинг с энергичным. Не надо долго думать, что бы выяснить, что разница на порядок будет на любом языке. Т.е. ленивый С++ в 10 реаз медленнее энергичного С++, если в лоб, как то сделано в linq.
Здравствуйте, alex_public, Вы писали:
G>>Это чтобы семантика соответствовала.
_>Ну т.е. в самой библиотеки .net нет ничего с нужной семантикой... )
В самой библиотеке есть парсер csv, он, что естественно, не заточен под такие вырожденые сценарии. Реальные csv вполне сносно парсит.
_>Потому что тут мы сравниваем библиотеки, а не языки.
Ога, библиотеки ориентированые на принципиально разные области.
_>Кстати, масштаб потребности можно легко увидеть введя в гугле например "csv .net" — т.к. в самой стандартной библиотеке решения нет, то инет переполнен вариантами. Ну а с помощью Boost'a полноценный csv парсер пишется в 3 строки, причём он ещё будет намного быстрее всех этих сторонних .net библиотек.
Да ладно, не гони. Раки и олени не могут заглянуть в соседний неймспейс.
_>Да какая разница какой объём. Даже если 100Кб, он всё равно будет тратить в 10 раз больше процессорного времени. Соответственно при постоянном пользование таким кривым софтом, время жизни от аккумулятора заметно уменьшается. Представляю сколько бы жили смартфоны, если например все браузерные движки были написаны в стиле java/.net...
В реальных приложениях процессинг минимум раз в 100 дольше, чем загрузка файла и его парсинг.
Здравствуйте, Ikemefula, Вы писали:
_>>Так твой пример же как раз чётко последовательный. В начале read, а потом write. Его нельзя переделать в параллельный даже если очень захочется. ))) I>Я могу запустить сколько угодно таких операций. Собственно так большей частью и происходит.
Да, можешь. И в C++ и в C#. И в обеих реализациях получишь некорректный код. Если конечно не вставишь какую-то синхронизацию в async_read. Но это уже другая история и опять же доступно в обеих реализациях.
I>Пока что не придумали хорошего способа поместить всю базу данных в локальную переменную со всеми таблицами, колонками и строчками.
Агааа. И ещё интересно зачем это в базах данных придумали такую странную вещь, как транзакции... )
Здравствуйте, Ikemefula, Вы писали:
I>Ты сравнил хрен с пальцем — ленивый процессинг с энергичным. Не надо долго думать, что бы выяснить, что разница на порядок будет на любом языке. Т.е. ленивый С++ в 10 реаз медленнее энергичного С++, если в лоб, как то сделано в linq.
С чего бы это? При нормальной статической реализации не должно быть никакой разницы в скорости.
Это если говорить вообще про ленивость. А если говорить про конкретный случай, то как раз Boost.Spirit весь построен на ленивости (через библиотеку Boost.Phoenix)! Там же все действия по обработке данных задаются прямо в грамматике, т.е. через ленивый код.
А вот как раз реализация gandjustas'а и является классической энергичной реализацией в лоб. И она уступила по скорости ленивой из spirit'a в 2 раза.