Re[12]: Mногопоточность: C++ vs Erlang vs другие
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.06.15 09:53
Оценка:
Здравствуйте, PM, Вы писали:

I>>Дело в том, что IO не вызывает JS сразу, как только получит его. Запрос проходит довольно большой препроцессинг прежде чем попадёт в JS.


PM>У вас устаревшая информация — libeio был полностью заменен на libuv где-то пару лет назад точно, в node.js версии 0.8. Емнип, разработчики node.js заколебались бороться с libeio и с 2011 года стали делать свой вариант асинхронного ввода/вывода.

PM>Внутри libuv банальный пул потоков (по умолчанию вроде бы 4) в котором выполняется ввод/вывод на файлах и сокетах.

Я не сильно в курсе хронологии либ для асинхронного IO в ноде, был libeio, libev, lubuv и может даже еще что нибудь. Это не сильно принципиально. Разница в основном в размере, всевозможных оптимизациях, поддержке на разных платформах и тд.

Вот, например
"Libeio is a full-featured asynchronous I/O library for C, modelled in similar style and spirit as libev"

libuv:"It was originally an abstraction around libev or Microsoft IOCP"
Re[12]: Mногопоточность: C++ vs Erlang vs другие
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.06.15 10:09
Оценка: :)
Здравствуйте, vdimas, Вы писали:

V>Именно что. Зато наоборот — дудки.

V>Поэтому, вопрос — нафига ты привел Node.js как пример? ))

Вообще-то не я.

V>Ты меня утомил еще тогда. Тебе объяснили и логику и код показали, но ты продолжал залетать вновь и вновь, утомив в итоге всех участников. Т.к. прошло уже достаточно времени и ты должен был подрасти, рекомендую пройтись по той ветке с новым пониманием. На тот момент понимания было ровно ноль.


Два года прошло а у тебя ровно те же аргументы

V>>>Конечно, дотнет это не детсад, но именно библиотека Task безбожно тормозит в сравнении с идентичными по архитектуре библиотеками TBB/PPL.

I>>Это слабая отмазка. Ты рассказывал про нод, а проблемы с асинхронщиной оказались в дотнете.

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


Нод уже работает в гораздо большем масштабе, нежели прототипирование и утилиты.

V>>>Ну как это БЕЗ жестких данных, если я рядом же в обсуждении дал затраты порядка 2-3 uSec задержек с картеек onload в юзер-мод драйверах?

I>>Смешно. Асинхронщина в дотнете гораздо тормознее.

V>Угу, аккурат на порядок.


То есть, твои жОсткие данные снова оказались лажей ?

V>Ты, не обладая инфой, проехался по С++, приведя как аргменты некие другие технологии:

V>http://rsdn.ru/forum/flame.comp/6069181.1
Автор: Ikemefula
Дата: 05.06.15


Раскрой глаза. В С++ уже давно развивается асинхронный IO в виде акторов, эвентов и тд и тд. Здесь целая пропасть самых разных либ на все случаи жизни.

V>Я привел TBB/PPL как аргумент против твоих аргументов, пройдясь по больным местам упомянутого тобой.


Не сильно в курсе твои баззвордов. Ты лучше прямо скажи — ты до сих пор уверен, что мутексы-семафоры и прочее разделяемое состояние и есть вершина мысли в С++ ? Если так, то ты застрял в девяностых
Re[13]: Mногопоточность: C++ vs Erlang vs другие
От: PM  
Дата: 09.06.15 10:30
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>Дело в том, что IO не вызывает JS сразу, как только получит его. Запрос проходит довольно большой препроцессинг прежде чем попадёт в JS.


PM>>У вас устаревшая информация...


I>Я не сильно в курсе хронологии либ для асинхронного IO в ноде, был libeio, libev, lubuv и может даже еще что нибудь. Это не сильно принципиально. Разница в основном в размере, всевозможных оптимизациях, поддержке на разных платформах и тд.


В теории это не принципиально, и нет различий между теорий и практикой, но на практике они есть. Мое несогласие еще относилось к выделенному.

Насколько я понимаю, большого препроцессинга в node.js нет — асинхронная операция выполняется в пуле потоков, её результат помещается в основной поток, где работает V8. В этом нет ничего сложного.
Re[19]: Mногопоточность: C++ vs Erlang vs другие
От: Evgeny.Panasyuk Россия  
Дата: 09.06.15 11:15
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Мне категорически не нравится тот синтаксис, который был предложен одним из авторов буста.


Синтаксис мне тоже не особо нравится, но я говорю не про синтаксис, а про внутреннюю реализацию. Используя оба варианта можно получить практически одинаковый синтаксис, что для await, что для yield.

V>Вот куда как более зрелые предложения:

V>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4134.pdf

Я его читал — это то что я называю proposal от Microsoft

V>Генератор должен вернуть итератор. Далее этот итератор обслуживается так же как все остальные итераторы, через for(var a : iterator), через алгоритмы STL и через аргументы стандартных контейнеров.

V>Согласись, что интерфейс итератора должен заметно отличаться от простого вызова ф-ии, возвращающей следующее значение.

Конечно должен быть итератор или range, а я разве говорил о другом? Тебе показать итераторы на базе макросов из Boost.Asio?

EP>>То всё состояние генератора спокойно может жить как автоматический/временный объект.

V>Да ради бога. Только генератор/трансформатор — это лишь очень частный случай для техники корутин, который, к тому же, никогда не будет принят в том виде, в котором его предлагает один из авторов буста. ))

1. Нормальное время жизни нужно не только генератору, это был конкретный пример.
2. Если ты прочитаешь N4134, ссылку на которое ты дал, то увидишь что генератор это один из мотивирующих примеров.

EP>>Если я захочу создать его в куче — то сделаю new natural{}, и т.п. — это обычный тип.

V>Возможно, так и будет. Пройдись, плиз, по ссылке.

Где конкретно? Я там вижу явные аллокаторы и вот такое:

An implementation is allowed to elide calls to the allocator’s allocate and deallocate functions and use stack memory of the caller instead if the meaning of the program will be unchanged except for the execution of the allocate and deallocate functions.

То есть сначала вводим неоптимиальную фичу, а потом заставляем компилятор её оптимизировать, в то время как можно было сделать сразу оптимальную.

EP>>Proposal же от microsoft подразумевает что будет некоторая явная аллокация, которую компилятор может оптимизировать, а может и нет.

V>Я тебе уже писал, что Proposal от microsoft вообще решает совсем другую задачу.

Одни из главных задач это await и yield, а в твоём понимании какую?

V>Ну натурально, если непонятно, при чем тут связка await c std::future, то в следующую итерацию мы остановимся на этом моменте и не пойдём дальше, пока не преодолеем его. ))


Связка await с future понятна, но она ортогональна реализации stackless корутин, и возможна в обоих вариантах.

V>В общем, я даю тебе установку (как Кашпировский) — основной сценарий вертится вокруг будущих расширений std::future (метод then). Твоя задача, даже если не согласиться с этим, но хотя бы понять, откуда ноги растут именно у этого направления.


Я реализовал await на stackful корутинах, который как раз цепляется к then. А асинхронные операции с await'ом как раз возвращают future.
Я прекрасно понимаю откуда ноги растут. И вот это совершенно ортогонально тому можно ли копировать всю корутину (в случае stackless) или нельзя.
Копируемые/перемещаемые корутины мощнее — на них например можно реализовать монаду List (через тот самый await), а на некопируемых — нет.

V>И еще перестать волноваться, бо это "направление" — тоже лишь одно из направлений, правда, самое важное на сегодня. Думаю, "легковесный" сценарий тоже в итоге прикрутят.


Его нужно прикручивать сразу.

V>Вот тебе пример:

V>
V>future<int> foo(int x) resumable
V>{
V>    auto y = await getY(x);  // (1)
V>    return await getZ(y);    // (2)
V>}; 
V>

V>Обрати внимание на сигнатуру, это принципиально.

И что в ней такого?

V>Итак, что здесь происходит в случае stackless-корутины:

V>- Мы вызываем foo(42) лишь однажды (сравнить с многократным явным заходом в твой генератор).

Многократный заход полностью под капотом. Точно также как в await C# — там внутри многократный заход в метод, в котором стоит switch, который прыгает на нужное состояние

V>- В первый раз тело foo гарантированно выполняется до точки (1).


Точно также как и в перелагаемом мной варианте.

V>- getY возвращает нам future, у этого future мы вызываем метод then, который цепляет остаток тела foo как продолжение (в дотнете в этом месте вызывается Task.ContinueWith(restOfMethodBody)).


Также как и в моём варианте.

V>- возвращаем вызывающему коду некое зарезервированное под результат ф-ии еще одно future.


Также как и в моём варианте.

V>- если в момент вызова метода then у future в точке (1) getY уже получил результат, то продолжение метода вызывается мгновенно из текущего потока, т.е. мы сразу переходим к (2) и далее аналогично как с (1).


Это лишь деталь реализации, но да — это тоже возможно.

V>- если в момент вызова then в точке (1) данные от getY еще не готовы, то продолжение тела foo будет вызывано из того потока, в котором самое первое future перейдет в состояние resolved.


Да.

V>Если же речь о выполнении аналогичного кода в statefull-корутине, то в точке (1) мы должны будем запросить создать некий примитив синхронизации прежде чем вернем управление, а затем ожидать этот примитив синхронизации на каком-нить пуле потоков+IOCP для обработки в момент готовности примитива синхронизации. Что тут хреново — это переключение контекстов, т.е. примитив синхронизации будет установлен в сигнальное значение в одном потоке, а продолжение будет вызвано в общем случае в другом потоке и м/у этими двумя событиями быдет относительно тяжеловесное срабатывание шедуллера, либо ядерного (для случая IOCP), либо пользовательского для какой-нить аналогичной технологии. Всё это — затраты и еще раз затраты, в то время как продолжение, прилепленное по then вызывается сразу же по переводу future в состояние ready.


О чём ты говоришь? Даже для stackful можно вернуть управление сразу же, если future уже готово.

EP>>На тех stackless корутинах о которых я говорю — реализуется и await и генераторы, и т.п. Они мощнее по возможностям.

V>Нет, не мощнее.

Мощнее.

V>Поэтому, если даже твой сценарий и реализуют, то это будет чистенько, типобезопасненько и полностью совместимо с интерфейсом уже имеющихся итераторов, т.е. алгоритмов STL, контейнеров и всяких новых синтаксисов for(auto a : generate()) { ... }.


Ты не понимаешь о чём идёт речь. Такой интерфейс можно сделать даже к stackless корутинам — макросам из Boost.Asio.


EP>>Почему? Я же не говорю что их нужно повторять в точности до синтаксиса и всех неудобств.

V>Ну потому что многократный явный вызов ЕДИНСТВЕННОЙ "точки входа" — это жесть, вообще-то. Это банально неумно. У интерфейса/контракта итератора должно быть больше одного метода, чтобы он был действительно полезной парадигмой.

То есть proposal ты не смотрел, короутины из Boost.Asio тоже, поэтому несколько методов и не видел


V>>>Потому что никакого контроля со стороны компилятора. Потому что одним неверным чихом можно всё поломать.

EP>>Именно поэтому и нужна стандартная фича.
V>Э, нет. Я говорю про асинхронные корутины, которые ты собрался делать на "обычных yield-генераторах".

Нет, я говорю о том что корутины могут быть копируемыми, перемещаемыми, сериализуемыми, быть обычными объектами без аллоцируемого состояния, и при этом иметь удобный синтаксис для await/yield и т.п.

EP>>>>Я надеюсь что proposal от Microsoft не пройдёт, а пройдёт от автора Boost.Asio.

V>>>Чур тебя))
V>>>Это ортогональные техники для непересекающихся сценариев.
EP>>Да ладно? И там и там реализуется await/async, и там и там реализуется yield — и в обоих случаях это является мотивирующими примерами
V>Но они НЕ взаимозаменяемы. У тебя НЕ будет способа выразить await через yield в простейшем же сценарии:

Почему ты думаешь что копируемость состояния помешает реализовать такой синтаксис?
Re[14]: Mногопоточность: C++ vs Erlang vs другие
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.06.15 12:59
Оценка:
Здравствуйте, PM, Вы писали:

PM>Насколько я понимаю, большого препроцессинга в node.js нет — асинхронная операция выполняется в пуле потоков, её результат помещается в основной поток, где работает V8. В этом нет ничего сложного.


Вопрос в том, что именно входит в эту асинхронную операцию.
Re[2]: Почему Эрланг
От: kostik78 США  
Дата: 09.06.15 13:54
Оценка:
много тут чего уже написали. Отвечу личный опыт на вопрос "почему Эрланг". При правильном применении Erlang/OTP скорость разработки платформы увеличиваеться в 4-5 раз по сравнению с Java(С++ оставлю за скобки так как серьезно не писал на нем лет 7-8 уже).

И потом тут уже говорили и пытались парировать что у Эрланага все плохо с обработкой данных(манипуляции с памятью). Да это правда — так и не пытайтесь его применить. Для этого есть Java или в конце концов pure C. Эрланг предоставляет достаточно возможностей для интеграции с другими языками. И NIF обычно расматриваеться как last resort для этого ибо в nif завалить vm легко. Я писал систему которая обрабатывала 10Gb поток и event processing был сделан на Erlang/OTP. Эрланг работал с железом через комбинацию C-node<->kernel space driver. И все работало и тормозов небыло потому что никто не пыталься поставить Эрланг раком. А система работала устойчиво и была написана в довольно быстрые сроки.

Что я люблю в Эралнг — так это то что мне дают надежный и провереный framework для построения fault tolerant систем и я фокусируюсь только на задаче которую мне нужно выполнить. У меня не болит голова как передать сообщение в процесс который вообще может быть запущен на другом сервере, мне не нужно тюнить GC под мой workload и т.п. И имхо, Go и Scala еще пилить и пилить до того же уровня надежности. Это мое практическое имхо.
Re[11]: Почему Эрланг
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.06.15 13:55
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Ну, вообще, самый большой плюс от future — это то, что они являются еще и монадами maybe {result, error}, с распространением исключений по всей связанной цепочке (в будущих расширениях, типа future::then). Да, на этом можно строить иерархии задач (графов агентов) с автоматическим распространением ошибки к некоему "корню".


Это не плюс, это собственно "по определению". Выполнение асинхронного кода идет кусочками, соответсвенно связь между цепочками это основной поток(flow) вычисления + поток(flow) ошибок. Т.е. ровно то же, что и унутре каждой цепочки.

Собственно отсюда и растут проблемы с глобальным состоянием.

Вот, например

var x = readFile('path')
var i = readGlobalState(x);
var y = ajaxPost(x);
writeGlobalState(i);

return toJson(y);


Код выглядит как синхронный, но на самом деле он может быть и асинхронным. Проблемы с глобальным состоянием во весь рост — те самые гонки, "которых нет". Теперь пример сложнее
try{
  var x = readFile('path')
  var i = readGlobalState(x);
  var y = ajaxPost(x);
  writeGlobalState(i);

  return toJson(y);
} catch(e) {
  return errorToJson(e);
} finally() {
  writeGlobalState(i);
}


Здесь тоже не ясно, что к чему. Скажем, если унутре короутины, то снова получаем асинхронный код. И снова проблемы с глобальным состоянием во весь рост — те самые гонки, "которых нет".

Предположим, readFile бросает исключение и код синхронный. Все в порядке — заходим и в catch, и в finally
А если код асинхронный — почему должно быть как то иначе ?

Теперь про агентов — в коде выше в асинхронном варианте в обоих вариантах есть гонки, это общая проблема любой многозадачности, а не так, как думают сельские крымские разработчики (только в вытесняющей)

На одних только then никаких агентов не построишь. Агенты строятся исключительно за счет изолирования состояния. then это всего лишь связывание цепочек, никакого отношения к изолированому состоянию оно не имеет. Как видно, асинхронные варианты выше имеют в полный рост проблемы с глобальным состоянием. Далее, изолированое состояние требуют обмен сообщениями, что, в сумме означает следующее — никаких then вообще не нужно для агентов основаных на монаде Future/Promise и тд.
Вместо этого нужны обычные эвенты и очереди вызовов. Что будет унутре очереди и на чем она будет построена — вообще дело десятое.
Отредактировано 09.06.2015 14:53 Pauel . Предыдущая версия .
Re[15]: Mногопоточность: C++ vs Erlang vs другие
От: PM  
Дата: 09.06.15 14:08
Оценка:
Здравствуйте, Ikemefula, Вы писали:


PM>>Насколько я понимаю, большого препроцессинга в node.js нет — асинхронная операция выполняется в пуле потоков, её результат помещается в основной поток, где работает V8. В этом нет ничего сложного.


I>Вопрос в том, что именно входит в эту асинхронную операцию.


Это не вопрос — код открыт, можно посмотреть.

Например посмотрим на функцию fs.readFile(). Там происходит асинхронное открытие файла, создание буфера необходимого размера и вызов функции fs.read(). В ней мы видим, что создается запрос на асинхронную операцию FSReqWrap и вызов С++ функции binding.read() с этим запросом, буфером, смещением в файле в качестве аргументов.

В С++ реализации binding.read aka Read происходит распаковка аргументов из V8 values. Далее происходит асинхронный (если передана FSReqWrap) или синхронный вызвов uv_fs_read() с callback функцией завершения After(). Функция uv_fs_read() — это обертка на системным API: асинхронный ReadFile() на Windows или какой-нибудь [p]readv() на *nix системах.

В функции завершения асинхронной операции проверяется ее результат и вызывается JavaScript callback, хранящийся в FSReqWrap.

Всё, ничего нового. Единственная тонкость — libuv спроектрована так, чтобы вызывать After callback в том же потоке, где работатет V8.
Re[12]: Почему Эрланг
От: so5team https://stiffstream.com
Дата: 09.06.15 14:27
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Агенты строятся исключительно за счет изолирования глобального состояния.


Сложно воспринять "изолирования" и "глобального" в одном предложении. Состояние либо глобальное, либо изолированное, имхо.
Собственно, агенты/акторы имеют свое собственное состояние, изолированное от состояния других агентов. В этом-то и их смысл.

Возможно, вы именно это и говорили, но я не распарсил, потому решил уточнить.
Re[13]: Почему Эрланг
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.06.15 14:33
Оценка:
Здравствуйте, so5team, Вы писали:

I>>Агенты строятся исключительно за счет изолирования глобального состояния.


S>Сложно воспринять "изолирования" и "глобального" в одном предложении. Состояние либо глобальное, либо изолированное, имхо.

S>Собственно, агенты/акторы имеют свое собственное состояние, изолированное от состояния других агентов. В этом-то и их смысл.

Да, я немного поторопился. Глобальное — доступное всем. Разделяемое — доступное некоторым. Изолированое — своё у каждого.
Соответственно нужно отказываться не только от глобального, но и от разделяемого состояния.
Re[16]: Mногопоточность: C++ vs Erlang vs другие
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.06.15 14:47
Оценка:
Здравствуйте, PM, Вы писали:

PM>В функции завершения асинхронной операции проверяется ее результат и вызывается JavaScript callback, хранящийся в FSReqWrap.


PM>Всё, ничего нового. Единственная тонкость — libuv спроектрована так, чтобы вызывать After callback в том же потоке, где работатет V8.


readFile это просто. Вопрос — в каком потоке выделяется память под всякие буферы, колбеки и тд ?
Вот с нетворком не совсем ясно, например TCPWrap::OnConnection
Она в каком потоке выполняется ?

А вот тот же http_parser — он в каком потоке работает ? С шифрованием, если принимаем расшифрованый контент, в каком потоке работает сам шифровальщик ?
Re[12]: Почему Эрланг
От: vdimas Россия  
Дата: 09.06.15 21:53
Оценка:
Здравствуйте, Ikemefula, Вы писали:

V>>Ну, вообще, самый большой плюс от future — это то, что они являются еще и монадами maybe {result, error}, с распространением исключений по всей связанной цепочке (в будущих расширениях, типа future::then). Да, на этом можно строить иерархии задач (графов агентов) с автоматическим распространением ошибки к некоему "корню".


I> Это не плюс, это собственно "по определению".


Это просто инструмент, которым можно вот этот конкретный сценарий, совпадающий с путем распространения ошибки "по-умолчанию", решить задешево. Но в реальной жизни приходится пути распространения ошибок корректировать.

I>Выполнение асинхронного кода идет кусочками, соответсвенно связь между цепочками это основной поток(flow) вычисления + поток(flow) ошибок. Т.е. ровно то же, что и унутре каждой цепочки.


Это можно сказать и про синхронный код, про каждый вызов АПИ ОС. Не в этом дело.

I>Собственно отсюда и растут проблемы с глобальным состоянием.


Если честно, я плохо понимаю, откуда ты постоянно берешь своё "глобальное состояние".

I>Вот, например


I>
I>var x = readFile('path')
I>var i = readGlobalState(x);
I>var y = ajaxPost(x);
I>writeGlobalState(i);

I>return toJson(y);
I>


I>Код выглядит как синхронный, но на самом деле он может быть и асинхронным. Проблемы с глобальным состоянием во весь рост — те самые гонки, "которых нет". Теперь пример сложнее


Не надо. Ты приводишь нелепые сниппеты на нелепых языках на нелепых фреймворках. Мы и так знаем, что там всё не просто ))
Да, у JS есть такая страшная хрень как "контекст", это такая же точно гиря как в случае с Лиспом и все побочные эффекты от "контекста" были известны еще десятки лет назад. Я рад, что ты, наконец, открываешь эти эффекты для себя.

I>Теперь про агентов — в коде выше в асинхронном варианте в обоих вариантах есть гонки, это общая проблема любой многозадачности, а не так, как думают сельские крымские разработчики (только в вытесняющей)


Тебе уже сотни раз рекомендовалось поинтересоваться, что есть "гонки". Ты называешь этим термином нечто, что уже 3-й год весь форум не в состоянии идентифицировать.

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

I>На одних только then никаких агентов не построишь.


Ну ващет, построишь, там же на них можно ветвится — это же бинарная монада, т.е. можно сэмулировать тьюринг-полную систему, а далее ты в курсе.

I>Агенты строятся исключительно за счет изолирования состояния.


Потеки сознания.
А инкапсуляция состояния в обычных объектах — без изолирования? ))
Агенты — это сугубо парадигма и ничего более. Простая парадигма, надо сказать. Покурить её сам на этот раз сходишь или отправить?))


I>then это всего лишь связывание цепочек


Наоборот — для разрывания последовательных операций
Вот ты жжешь, коллега...

Берем некий изначально "непрерывный" алгоритм, режем этот алгоритм на куски с помощью then (в дотнете Task.ContinueWith, которое генерит компилятор на месте await).

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

I>Как видно, асинхронные варианты выше имеют в полный рост проблемы с глобальным состоянием.


Очередные потеки.
Отредактировано 09.06.2015 22:02 vdimas . Предыдущая версия .
Re[14]: Почему Эрланг
От: vdimas Россия  
Дата: 09.06.15 21:55
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Да, я немного поторопился. Глобальное — доступное всем. Разделяемое — доступное некоторым. Изолированое — своё у каждого.

I>Соответственно нужно отказываться не только от глобального, но и от разделяемого состояния.

Т.е. надо отказаться от очередей сообщений?
Опять поторопился? ))
Re[13]: Почему Эрланг
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.06.15 08:04
Оценка:
Здравствуйте, vdimas, Вы писали:

I>> Это не плюс, это собственно "по определению".


V>Это просто инструмент, которым можно вот этот конкретный сценарий, совпадающий с путем распространения ошибки "по-умолчанию", решить задешево. Но в реальной жизни приходится пути распространения ошибок корректировать.


Это одно и то же.

I>>Выполнение асинхронного кода идет кусочками, соответсвенно связь между цепочками это основной поток(flow) вычисления + поток(flow) ошибок. Т.е. ровно то же, что и унутре каждой цепочки.


V>Это можно сказать и про синхронный код, про каждый вызов АПИ ОС. Не в этом дело.


Именно в этом. Синхронный код поддерживается синтаксисом ЯП. Вот для асинхронного кода ничего такого нет в мейнстриме.

I>>Собственно отсюда и растут проблемы с глобальным состоянием.


V>Если честно, я плохо понимаю, откуда ты постоянно берешь своё "глобальное состояние".


Уже просто любая глобальная переменная уже показывает все проблемы.

I>>Вот, например


I>>
I>>var x = readFile('path')
I>>var i = readGlobalState(x);
I>>var y = ajaxPost(x);
I>>writeGlobalState(i);

I>>return toJson(y);
I>>


V>Тебе уже сотни раз рекомендовалось поинтересоваться, что есть "гонки". Ты называешь этим термином нечто, что уже 3-й год весь форум не в состоянии идентифицировать.


"Недетерминированный порядок исполнения двух задач"

Если непонятно — можешь рассматривать код выше как небольшой фрагмент применения зеленых потоков. Разницы абсолютно никакой. Все проблемы абсолютно одинаковы.

V>Например, даже любимый твой Майкрософт в доках пишет, что кооперативная многозадачность позволяется избегать лишних гонок и лишних же блокировок. Но у тебя как был затык в понимании "гонок", так и не рассосался до сих пор. И ведь не страшно же тебе на весь интернет так подставляться, не? )) С работы не уволят, случаем? ))


Микрософт говорит совсем про другое. См пример выше. Этот код задачи, таких в джаваскрипте можно запустить хоть тысячу за раз. Все они будут работать в одном потоке по правилам кооперативной многозадачности. Собтсвенно, ровно ничем не отличается от зеленых потоков.
Отсюда получаем тот самый "недетерминированый порядок"

I>>Агенты строятся исключительно за счет изолирования состояния.


V>Потеки сознания.

V>А инкапсуляция состояния в обычных объектах — без изолирования? ))

Именно. Если твой объект используется из разных задач, что будет ? Если класс инкапсулирует всего лишь указатель на разделяемый ресурс ?
Инкапсуляция — во весь рост, изоляции — ноль.

I>>then это всего лишь связывание цепочек


V>Наоборот — для разрывания последовательных операций

V>Берем некий изначально "непрерывный" алгоритм, режем этот алгоритм на куски с помощью then (в дотнете Task.ContinueWith, которое генерит компилятор на месте await).

Это не разрезание, а связывание. Задача состоит из кусков, которые, возможно, выполняются в разных потоках, или, например, задача прибита к эвентлупу.

V>И все это с единственной целью — уйти от вытесняющей ядерной многозадачности в сторону кооперативной юзверской.


У тебя должен быть хороший ответ — как 1000 зеленых потоков смогут корректно работать с глобальным состоянием.
Re[15]: Почему Эрланг
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.06.15 08:08
Оценка:
Здравствуйте, vdimas, Вы писали:

I>>Да, я немного поторопился. Глобальное — доступное всем. Разделяемое — доступное некоторым. Изолированое — своё у каждого.

I>>Соответственно нужно отказываться не только от глобального, но и от разделяемого состояния.

V>Т.е. надо отказаться от очередей сообщений?

V>Опять поторопился? ))

Работу с такой очередью берет на себя или язык, или фремворк.
Re[20]: Mногопоточность: C++ vs Erlang vs другие
От: vdimas Россия  
Дата: 10.06.15 20:14
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Нет, я говорю о том что корутины могут быть копируемыми, перемещаемыми, сериализуемыми, быть обычными объектами без аллоцируемого состояния, и при этом иметь удобный синтаксис для await/yield и т.п.


Ну ОК.
Не мог бы ты показать конкретные примеры из твой твоей ссылки proposal от одного из авторов буста, чтобы я точно знал, что мы обсуждаем одно и то же. Я прочел только первую половину и практически со всем написанным там не согласен. Похоже, мы сейчас заочно обсуждаем разные вещи.

Что интересует? Связь синтаксиса и семантики. По синтаксису в текущих proposal stackless-корутина может представлять из себя просто resumable ф-ию, в которой отсутствуют уши низлежащего механизма. Покажи, как "копировать ф-ию"?
Re[21]: Mногопоточность: C++ vs Erlang vs другие
От: Evgeny.Panasyuk Россия  
Дата: 10.06.15 21:44
Оценка:
Здравствуйте, vdimas, Вы писали:

EP>>Нет, я говорю о том что корутины могут быть копируемыми, перемещаемыми, сериализуемыми, быть обычными объектами без аллоцируемого состояния, и при этом иметь удобный синтаксис для await/yield и т.п.

V>Ну ОК.
V>Не мог бы ты показать конкретные примеры из твой твоей ссылки proposal от одного из авторов буста, чтобы я точно знал, что мы обсуждаем одно и то же. Я прочел только первую половину и практически со всем написанным там не согласен. Похоже, мы сейчас заочно обсуждаем разные вещи.

Я прежде всего говорю о методе управления состоянием корутины, а конкретно в каком виде оно хранится и что с ним можно делать.

В Proposal от Microsoft — n4134 — состояние аллоцируется аллокатором определённым в resumable_traits. Сколько нужно места под это состояние — заранее неизвестно, также это состояние нельзя копировать/перемещать, и поэтому в общем случае оно будет жить в куче, откуда следуют неизбежные тормоза.
Например нельзя вернуть из функции саму корутину со всем состоянием — это всегда будет некоторый хэндл на состояние размещённое в куче.

В Proposal от автора Boost.Asio — n4244 — корутина со всем её состоянием это фактически объект обычного класса, поля которого полностью определяют состояние корутины. Размер всего состояния это всего лишь sizeof этого класса, поэтому его легко создавать на стэке, да и вообще где угодно. Поля такого объекта можно перемещать/копировать/сериализовывать/и т.п.
Layout такого класса (с оптимизациями типа union для полей из соседних scope) разобран в главе "13 Implementation approach". Но если не вдаваться в детали оптимизаций и времени жизни, то для вот такой корутины (псевдокод, подобный синтаксис реализуем при обоих подходах к управлению состоянием):
future<int> sum()
{
    int x = await foo();
    int y = await bar();
    return x + y;
}
получается вот такой layout:
struct coroutine
{
    int internal_state; // i.e. current await point
    int x;
    int y;
    int result;
};


V>Что интересует? Связь синтаксиса и семантики. По синтаксису в текущих proposal stackless-корутина может представлять из себя просто resumable ф-ию, в которой отсутствуют уши низлежащего механизма.


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

V>Покажи, как "копировать ф-ию"?


Вот конкретный пример:
auto foo = [](auto continuation) // .then
{
    continuation(1);
    continuation(2);
    continuation(3);
};

auto bar = [](auto continuation) // .then
{
    continuation('a');
    continuation('b');
    continuation('c');
};

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;
        }
    };
};

int main()
{
    coroutine{}();
}
Вывод:
1 a
1 b
1 c
2 a
2 b
2 c
3 a
3 b
3 c
LIVE DEMO on Coliru
Это подобие List Monad, без копирования продолжения так не получится.
Отредактировано 10.06.2015 21:48 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 10.06.2015 21:46 Evgeny.Panasyuk . Предыдущая версия .
Re[7]: Почему Эрланг
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.06.15 15:42
Оценка: 3 (2) +1
Здравствуйте, so5team, Вы писали:

S>Полагаю, что 64-х битовые Linux, FreeBSD, Windows. На хорошем железе, да.

Угу. Реальность (http://blogs.technet.com/b/markrussinovich/archive/2009/07/08/3261309.aspx):

However, on a system with 2GB of RAM, Testlimit64 was able to create only 55,000 threads, far below the number it should have been able to if resident available memory was the limiter (2GB/24K = 89,000)

In this case, it’s the initial thread stack commit that causes the system to run out of virtual memory and the “paging file is too small” error. Once the commit level reached the size of RAM, the rate of thread creation slowed to a crawl because the system started thrashing, paging out stacks of threads created earlier to make room for the stacks of new threads, and the paging file had to expand. The results are the same when the –n switch is specified, because the threads have the same initial stack commitment.

Ну, то есть, действительно, можно запустить 100К нитей на системе с 4GB рамы. Но накладные расходы становятся неприемлемыми.
Это там ещё не измерялось быстродействие — сколько CPU останется после шедулера для обработки прикладной логики?

S>Но суть в другом: не нужно работать с потоками ОС так же, как с легковесными процессами Erlang-а.

Совершенно верно: вместо потоков ОС нужно использовать другие механизмы шедулинга, т.е. велосипедить свою реализацию подмножества Erlang-а, т.к. встроенные механизмы шедулинга не предназначены для высоких нагрузок.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Mногопоточность: C++ vs Erlang vs другие
От: Ночной Смотрящий Россия  
Дата: 11.06.15 19:36
Оценка: 1 (1) +1
Здравствуйте, vdimas, Вы писали:

V>Да плевать как оно реализуется. Можно сделать переключение по принципам кооперативной многозадачности (как в дотнете), т.е. в моменты обращения к "АПИ", которое может потенциально блочить текущий "логический" поток исполнения.


О чем это ты?

V>Думаю, ты неправильно понимаешь work stealing. 99% задач в реальных асинхронных сценариях того же дотнета ЖДУТ другие задачи (т.е. средний async-метод состоит из 2-х или более асинхронных вызовов внутри, собсно, затем async и нужен, чтобы породить автомат, у которого будет хотя бы два состояния, бо для одного состояния async не нужен, оно у нас и так есть). А это ожидание одной задачей сигнала от другой надо как-то обыгрывать.


И при чем тут work stealing? Work stealing дотнет применяет вовсе не для ожидания другой задачи (для этого там есть такая штука как зависимость задач). Work stealing в TPL используется для эффективной загрузки аппаратных потоков уже активированными задачами в очередях с минимизацией блокировок при работе с этими очередями. Это единственное для чего этот прием там нужен.
А задачи, ожидающие завершения другизх задач в эти очереди даже не попадают. Там все совершенно банально и никакого отношения к async автоматам не имеет. I/O задача при вызове IOCP коллбека просто активирует другую задачу и все. И соврешенно не важно, как эти задачи сформированы, руками при помощи ContinueWith или компилятором, построившим из линейного кода автомат.
А если внутри задачи ждать, то это как раз таки быстро поставит конвеер TPL раком, и work stealing только поспособствует тому, чтобы раком встало как можно больше аппаратных потоков.
Re[8]: Mногопоточность: C++ vs Erlang vs другие
От: Ночной Смотрящий Россия  
Дата: 11.06.15 19:44
Оценка:
Здравствуйте, Mamut, Вы писали:

M>- scheduler, у которого пустая очередь, может попросить другие scheduler'ы отдать ему процесс на обработку


Это и есть work stealing.

M>огромное количество внимание уделено внутренностям "scheduler'ов": все очереди lock-free


В процессе передачи от одного шедулера к другому вряд ли там полностью lock-free.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.