Здравствуйте, Ночной Смотрящий, Вы писали:
M>>огромное количество внимание уделено внутренностям "scheduler'ов": все очереди lock-free
НС>В процессе передачи от одного шедулера к другому вряд ли там полностью lock-free.
Здравствуйте, Sharov, Вы писали:
НС>>В процессе передачи от одного шедулера к другому вряд ли там полностью lock-free. S>Почему не полностью lock-free, что может мешать?
Я подробностей сейчас не помню, но там возникает логическая связь между очередями, которую при помощи CAS или заведения массива флажков не разрулишь.
Здравствуйте, Ночной Смотрящий, Вы писали:
M>>- scheduler, у которого пустая очередь, может попросить другие scheduler'ы отдать ему процесс на обработку НС>Это и есть work stealing.
Здравствуйте, Ночной Смотрящий, Вы писали:
V>>Да плевать как оно реализуется. Можно сделать переключение по принципам кооперативной многозадачности (как в дотнете), т.е. в моменты обращения к "АПИ", которое может потенциально блочить текущий "логический" поток исполнения. НС>О чем это ты?
О том, о чем написано. При вызове из тела Task другого асинхронного метода через await происходит переключение логических потоков по принципам кооперативной многозадачности.
V>>Думаю, ты неправильно понимаешь work stealing. 99% задач в реальных асинхронных сценариях того же дотнета ЖДУТ другие задачи (т.е. средний async-метод состоит из 2-х или более асинхронных вызовов внутри, собсно, затем async и нужен, чтобы породить автомат, у которого будет хотя бы два состояния, бо для одного состояния async не нужен, оно у нас и так есть). А это ожидание одной задачей сигнала от другой надо как-то обыгрывать.
НС>И при чем тут work stealing? Work stealing дотнет применяет вовсе не для ожидания другой задачи
Вообще-то тот шедуллер, идущий в поставке, который сидит на пуле потоков, он с версии 4.0 стал work-stealing.
Более того — lock-free, более того, теперь он наиболее дешев в режиме LIFO (из-за оссобенностей конструкции lock-free очереди, которая представляет из себя стек, скорее).
НС>(для этого там есть такая штука как зависимость задач).
Это при ожидании некоего task, а при порождении новой задачи?
НС>Work stealing в TPL используется для эффективной загрузки аппаратных потоков уже активированными задачами в очередях с минимизацией блокировок при работе с этими очередями. Это единственное для чего этот прием там нужен.
Ну, попытка в 2-х словах рассказать обо всех бенефитах Work stealing, да еще на основе lock-free очереди, которая поддерживает одиночный push из любого потока, но умеет делать лишь popAll, т.е. не умеет доставать поэлементно... Похвально, да..
В общем, там намного больше тонкостей и намного больше любопытных эффектов, чем можно описать в одном посте. К тому же, ты вводишь людей в заблуждение — уже активированные задачи (поставленные в очередь) лучше всего шедуллятся через round robin, а work stealing хорош именно для большого трафика самих событий постановки задач в очередь, т.е. для случая, когда сами задачи миниатюрные. То бишь, work stealing хорошо умеет только одно — дешево ставить задачу в очередь. В нейтивном варианте постановка в ту очередь на PPL занимает несколько десятков ns всего.
НС>А задачи, ожидающие завершения другизх задач в эти очереди даже не попадают.
Ну вот я и предлагал коллеге подумать, как оно там происходит.
Потому что речь всё время об расширении std::future такими вещами как then, when_all, when_any. Всё это — как раз та самая простая связь задач, не требующая шедуллера. Вот тут расписывал подробней: http://rsdn.ru/forum/flame.comp/6072524.1
НС>Там все совершенно банально и никакого отношения к async автоматам не имеет.
Э, нет. Не банально. Очередь специфическая, решает проблему ABA весьма остроумным способом. Скажу так, на этом сайте, когда шло активное обсуждение lock-free алгоритмов, этот способ никем не упоминался. Ваш покорный слуга по основной работе когда-то давно "изобрел" этот трюк (и он используется в ядре продуктов нашей конторы), а спустя несколько лет потом увидел аналогичный трюк в MS PPL и в 4-м дотнете по их выходу. ))
НС>I/O задача при вызове IOCP коллбека просто активирует другую задачу и все. И соврешенно не важно, как эти задачи сформированы, руками при помощи ContinueWith или компилятором, построившим из линейного кода автомат.
И тут не всё так просто. Возможна ситуация, когда все потоки из пула загружены тасками, порождающими другие асинхронные таски безо-всякого ввода-вывода. Не заглядывая в доку предположи — кто и как слушает IOCP при этом и слушает ли? ))
НС>А если внутри задачи ждать, то это как раз таки быстро поставит конвеер TPL раком, и work stealing только поспособствует тому, чтобы раком встало как можно больше аппаратных потоков.
Речь шла о логическом потоке. В любом случае, логический поток всегда ждет выполнения другой задачи, т.е. блокирован. Используя пул потоков мы лишь убегаем от ядерного переключения логических потоков (в точках ожидания) в пользу юзверского переключения потоков (автоматов-тасков в дотнете), и всех делов.
Т.е. вся эта мышиная возня исключительно из-за того, что в современных архитектурах/ОС переключение потока ядром неприлично дорогое.
Здравствуйте, Sinclair, Вы писали:
S>Это там ещё не измерялось быстродействие — сколько CPU останется после шедулера для обработки прикладной логики?
Смотря на каких задачах. Если в ситуациях, когда все 100K нитей готовы к работе и нуждаются в кванте процессорного времени, то еще более интересно, как с такой ситуацией будет справляться расхваливаемый здесь Erlang.
S>Совершенно верно: вместо потоков ОС нужно использовать другие механизмы шедулинга, т.е. велосипедить свою реализацию подмножества Erlang-а, т.к. встроенные механизмы шедулинга не предназначены для высоких нагрузок.
Покажите, пожалуйста, что для этих целей предназначен Erlang.
А то вот буквально рядом
свидетели Erlang-а рассказывают, что большие объемы данных обрабатываются не без помощи написанных на plan-C нод. А ведь нода -- это отнюдь не мелкая NIF-ка.
Чтобы уметь копировать состояние, тебе это состояние надо в явном виде, в виде структуры/объекта. Я именно про это и написал, что тебе надо, чтобы для тебя "торчали уши" низлежащего механизма. Потому что resumable function из текущих proposal возвращает future или iterator, т.е. мы можем копировать только этот future или iterator.
(Кстате, для случая итератора, если поднапрячься, можно сделать примерно то, что ты хочешь, но не факт, что это будут делать)
Так вот, если уши торчат, как в твоём примере, то нафига это тянуть в стандарт? Пусть они себе торчат на уровне третьесторонних библиотек. Показанный синтаксис вполне меня устраивает. Уши видны, прекрасно понятно, что происходит.
Здравствуйте, vdimas, Вы писали:
V>Ну вот, ЧТД: V>
EP>>struct coroutine : asio::coroutine
EP>>{
V>
V>Чтобы уметь копировать состояние, тебе это состояние надо в явном виде, в виде структуры/объекта. Я именно про это и написал, что тебе надо, чтобы для тебя "торчали уши" низлежащего механизма.
Никакое не ЧТД
Что мешает вот это:
future<void> coroutine()
{
int x = await foo;
char y = await bar;
cout << x << " " << y << endl;
}
Преобразовать вот в это:
struct coroutine : asio::coroutine
{
int x;
char y;
void operator()()
{
reenter(*this)
{
await(x, foo); // x = await foo;
await(y, bar); // y = await bar;
cout << x << " " << y << endl;
}
};
};
?
Более того, в C# именно подобное преобразование и происходит.
V>Так вот, если уши торчат, как в твоём примере, то нафига это тянуть в стандарт?
Я не предлагаю в стандарт тянуть эмуляцию на макросах. Ещё раз, я показываю как оно может быть устроенно внутри.
Здравствуйте, vdimas, Вы писали:
V>О том, о чем написано. При вызове из тела Task другого асинхронного метода через await происходит переключение логических потоков по принципам кооперативной многозадачности.
Мдя. Ничего там не происходит. По await метод просто режется, и неважно, в теле другого таска или где то еще. Но к зависимостям задач это отношения не имеет. Хуже того, await вобщем то никак на Task не завязан, ему нужен только awaiter. И уж точно никакого переключающего вызова API тут нет, это чисто статическая штука. Ты же сам писал про то что yield и await это близнецы-братья.
НС>>И при чем тут work stealing? Work stealing дотнет применяет вовсе не для ожидания другой задачи V>Вообще-то тот шедуллер, идущий в поставке, который сидит на пуле потоков, он с версии 4.0 стал work-stealing. Более того — lock-free, более того, теперь он наиболее дешев в режиме LIFO (из-за оссобенностей конструкции lock-free очереди, которая представляет из себя стек, скорее).
Я в курсе. Я его код почти весь прочел. Поэтому и говорю, что work stealing никакого отношения к ожиданию IO не имеет.
НС>>(для этого там есть такая штука как зависимость задач). V>Это при ожидании некоего task, а при порождении новой задачи?
Зависимость создается автоматически. И это по прежнему никакого отношения к work stealing не имеет.
V>В общем, там намного больше тонкостей и намного больше любопытных эффектов, чем можно описать в одном посте.
Какие уж тут тонкости, если ты какие то ожидания приплел. С work stealing нет никаких суперсложностей. В дизайн-документе TPL на все описание хватило пары абзацев ЕМНИП. Да и в исходниках тоже все довольно тривиально. Открываешь ConcurrentBag.cs и читаешь.
V> К тому же, ты вводишь людей в заблуждение — уже активированные задачи (поставленные в очередь) лучше всего шедуллятся через round robin
Уж не знаю лучше или хуже, но вот TPL использует для этого очереди, привязанные к потокам + work stealing.
V>То бишь, work stealing хорошо умеет только одно — дешево ставить задачу в очередь.
Вот только в TPL этого нет.
V> В нейтивном варианте постановка в ту очередь на PPL занимает несколько десятков ns всего.
В TPL тоже все сравнительно быстро. Но при чем здесь ожидание задач?
НС>>Там все совершенно банально и никакого отношения к async автоматам не имеет. V>Э, нет. Не банально. Очередь специфическая, решает проблему ABA весьма остроумным способом. Скажу так, на этом сайте, когда шло активное обсуждение lock-free алгоритмов, этот способ никем не упоминался.
Какой способ? Локализация данных по потокам с целью уменьшения блокировок? Довольно стандартный прием. ConcurrentBag вообще сравнительно простой. Фокусы с массивом флажков в ConcurrentQueue, а уж тем более детали реализации ConcurrentDictionary намного интереснее.
Но это, опять же, совсем другая тема.
НС>>I/O задача при вызове IOCP коллбека просто активирует другую задачу и все. И соврешенно не важно, как эти задачи сформированы, руками при помощи ContinueWith или компилятором, построившим из линейного кода автомат. V>И тут не всё так просто. Возможна ситуация, когда все потоки из пула загружены тасками, порождающими другие асинхронные таски безо-всякого ввода-вывода.
Возможна. Именно для этого там очереди. Какая связь с тем кто кого порождает непонятно.
V> Не заглядывая в доку предположи — кто и как слушает IOCP при этом и слушает ли? ))
Ничего не понял. IOCP вообще не дело TPL. Это особенность реализации конкретных методов конкретного асинхронного API. Если у тебя задача чисто вычислительная, то и IOCP не нужен. Но ты то там задвигал про ожидание IO.
НС>>А если внутри задачи ждать, то это как раз таки быстро поставит конвеер TPL раком, и work stealing только поспособствует тому, чтобы раком встало как можно больше аппаратных потоков. V>Речь шла о логическом потоке. В любом случае, логический поток всегда ждет выполнения другой задачи, т.е. блокирован.
В рамках TPL это крайне плохая практика, ставящая, как я уже писал, TPL раком. Суть fork/join состоит в том, чтобы нарезать задачу на куски, которые ничего не ждут и связать их зависимостями. А уж сделано это вручную или при помощи написания в нужных местах await — никакой роли не имеет.
И опять это совсем другая тема, к work stealing отношения не имеющая.
V> Используя пул потоков мы лишь убегаем от ядерного переключения логических потоков
Здравствуйте, Ночной Смотрящий, Вы писали:
EP>>Если "попросить" — то это work requesting. НС>А если грохнуть шедулер, у которого мы попросили, то это work robbing?
Здравствуйте, Ночной Смотрящий, Вы писали:
EP>>Если "попросить" — то это work requesting. НС>А если грохнуть шедулер, у которого мы попросили, то это work robbing?
А вообще я серьёзно, work-stealing и work-requesting — это разные механизмы. remark вот тут резюмировал.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Мдя. Ничего там не происходит. По await метод просто режется, и неважно, в теле другого таска или где то еще. Но к зависимостям задач это отношения не имеет. Хуже того, await вобщем то никак на Task не завязан, ему нужен только awaiter. И уж точно никакого переключающего вызова API тут нет, это чисто статическая штука. Ты же сам писал про то что yield и await это близнецы-братья.
Это и есть кооперативная многозадачность. Фактически, один таск сам передаёт управление другому, только не напрямую, а через шедулер.
Здравствуйте, Ikemefula, Вы писали:
I>Это и есть кооперативная многозадачность.
Можно, конечно, и так это интерпретировать, но это ведет к неверному пониманию сути и потере важных деталей. Принципиальное отличие от типичной кооперативной многозадачности навроде той, что здесь про ghc Булат рассказывал, или той что в Win 3.X была в том, что "передача управления" происходит не по принципу "где угодно, но почаще", а во вполне конкретных точках. И это не просто прерывание исполнения с возвратом управления шедулеру (этого мало), но еще и явно декларированная логическая зависимость между частями кода. И этой зависимостью TPL, в отличие от кооперативного шедулера, активно пользуется.
Т.е. абстракция существенно более тонкая, завязанная на особенности исполнения.
I> Фактически, один таск сам передаёт управление другому, только не напрямую, а через шедулер.
Не все так просто. Один таск может передать управление нескольким, несколько тасков могут передать управление одному, таск может передать управление сам себе, есть особый вид тасков, который может сегментироваться по пожеланиям конвеера исполнения TPL и т.д. Причем все эти вещи явно декларируются, а не вычисляются в процессе работы.
Здравствуйте, meadow_meal, Вы писали:
_>В разработке очень удобно, например, у нас ребята часто работают парами, серверный программист и клиентский (например, Unity3d). Когда клиентский в игровой сессии тестирует новую функциональность или ловит баг, серверный может поправить код и нажать Ctrl+S, и это сразу отразится на том, что видит клиентский, ему не нужно даже игровую сессию перезапускать, перелогиниваться. С С++ можно пойти чаю попить, пока перекомпилируется все, пока заново в игру зайдешь, пока проблему воссоздашь.
Но ведь С++ то не единственная альтернатива. Java или дотнет и компилируются секунды, и прекрасно позволяют перезагружать классы/сборки на ходу.
_>Ну и интроспекция конечно
Здравствуйте, so5team, Вы писали:
S>Да, в этом и суть. Люди столкнулись с конкретной задачей. Они решили ее на привычных языках с привлечением готовых инструментов. Что является очередным примером того, что задачи из области parallel- и distributed computing совершенно спокойно решаются и без Erlang-а.
Для задач parallel computing Erlang вообще не годится, по целой куче причин, что об этом вспоминать?
Здравствуйте, Ночной Смотрящий, Вы писали:
F>>но если уж мы решили померять, кто лучше энларга НС>Лучше для чего? Вот ведь в чем вопрос то.
это неважно, как ни странно, т.к. нужна хоть какая-то точка отсчёта.
я предложил список широкоизвестных фич.
F>>, то стоит сравнить с его основными фичами, которые дают удобство, скорость и дешевизну разработки. НС>Разработки чего? Прежде чем заводить споры X vs Y неплохо бы определиться с областью применимости.
стоит начать хоть с какого-то минимума, нежели сразу пытаться охватить необъятное с высоты "своего опыта".
постепенно можно разложить по полочкам плюсы и минусы, определиться с ограничениями и лучшей областью применения.
иначе весь разговор превращается в маркетинговую фаллометрию.
я бы и рад убедиться в "лучшести" других инструментов, но по обрывочным фразам этого не понять.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Но ведь С++ то не единственная альтернатива. Java или дотнет и компилируются секунды, и прекрасно позволяют перезагружать классы/сборки на ходу.
дотнет на серваках держать не хочется, т.к. весь стек знакомых технологий далёк от винды. цена перехода слишком большая.
а у жавы проблемы с распределённостью. только akka вроде дала нужные плюшки. но это уже половина эрланга.
Здравствуйте, neFormal, Вы писали:
НС>>Лучше для чего? Вот ведь в чем вопрос то. F>это неважно
А, ну тогда все понятно.
F>>>, то стоит сравнить с его основными фичами, которые дают удобство, скорость и дешевизну разработки. НС>>Разработки чего? Прежде чем заводить споры X vs Y неплохо бы определиться с областью применимости. F>стоит начать хоть с какого-то минимума
С какого?
F>иначе весь разговор превращается в маркетинговую фаллометрию.
Он с самого начала уже такой.
F>я бы и рад убедиться в "лучшести" других инструментов, но по обрывочным фразам этого не понять.
Да тут дело даже не в лучшести. Для parallel computing Erlang просто не годится. А раз так, то то что пишет vdimas вообще не в тему, так как все эти work stealing и lock free важны строго для parallel computing.
Но даже и в рамках concurrency у Erlang куча ограничений. Про проблемы с GUI, к примеру, Ikemefula уже писал.
Так что, когда Мамут пытается тут нам рассказать, что ничего круче Ерланга нет, не указывая область применимости, то он, мягко говоря, не совсем прав. И главная проблема Ерланга именно что в весьма узкой области его применимости, а не в тонкостях работы VM.