Re[8]: Facebook и язык D - первый шаг наверх.
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.11.13 13:47
Оценка:
Здравствуйте, gandjustas, Вы писали:

Pzz>>Моно — это пионерская поделка, годящаясь только на то, чтобы изготавливать пионерские поделки. Существенной проблемой при этом является то, что пионеры не в состоянии понять, что кроссплатформенные пионерские поделки надо тестировать на всех платформах, а не только на любимом компьютере разработчила. Поэтому даже для изготовления кроссплатформенных пионерских поделок моно не годится. А пионерские поделки под венду проще все же делать, используя родные для венды средства.


G>А что мешает протестировать моно на разных компьютерах?


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

G>Кстати я собирал в студии проект который взлете на mono. Я наверное что-то не так сделал.


Я думаю, это был очень простой проект.
Re[10]: Facebook и язык D - первый шаг наверх.
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.11.13 13:49
Оценка: :)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Плохой пример чего? Ты о чём? matumba считал что Linux это C++


Плохой пример чего бы то ни было, кроме писания монолитных ядер юникс-подобных ОС. Ядро линуха очень похоже на другие подобные ядра, и очень мало похоже на какие-либо другие программы.
Re[30]: Facebook и язык D - первый шаг наверх.
От: Evgeny.Panasyuk Россия  
Дата: 10.11.13 13:55
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Да и в общем случае сделать из синхронного черного ящика асинхронный нельзя, потому что нет гарантии не нарушения инвариантов.


Придумай хотя бы пару примеров поломки инвариантов в функции которая принимает пользовательский stream, и гарантированно работает в многопоточной среде.
Re[30]: Facebook и язык D - первый шаг наверх.
От: alex_public  
Дата: 10.11.13 14:04
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>Ты понять показываешь незнание предмета. Какой вариант по твоему лучший?


IOCP использовался задолго до появления async\await. Это как раз и есть лучший вариант для систем со множеством параллельных операций и дополнительные накладные расходу от async\await ему совершенно ни к чему.

G>Тут не надо. Тут достаточно потока.


Ага. И я пока что вижу твою неспособность повторить на C# даже такой простейший вариант.

G>Но видимо тупо везде создавать потоки неэффективно, поэтому и придумали IOCP, пулы потоков, таски и async\await.


Только все эти вещи не завязаны друг на друга, а существую параллельно. Каждая для своих целей.

G>Это зависит от того что за фоновый процесс. Если там IO, то создание потоков — совсем не оптимальный способ. А практика показывает что подобные фоновые процессы в 99% случаев — io.


С чего бы это? Накладные расходы на переключение контекстов при таком раскладе вообще не принципиальны.

G>Ты о чем вообще? Для чего тебе леговесные потоки?


Я о сравнение накладных расходов у async/await из C# и аналогичных реализаций (например Boost.Coroutine)...

G>Ок, давай конкретнее, если сам мозгом не работаешь:


Что-то ты утомил своими кривыми отмазками. Каждому же в темке видно как ты пытаешься увильнуть от своих слов. Надоело это. Всё, есть всего два возможных варианта:

1. Ты признаешь, что реализация async/await C# слабее чем простейший вариант в десяток строк на C++.
2. Ты показываешь полный аналог этого http://www.rsdn.ru/forum/philosophy/5357968
Автор: alex_public
Дата: 09.11.13
кода. Если очень хочешь, то можешь с такой http://www.rsdn.ru/forum/philosophy/5358433
Автор: alex_public
Дата: 10.11.13
поправкой (вариант без ненавистных тебе потоков). И мы все признаём, что реализация на C# не слабее.

Если в последующих твоих сообщениях не будет одного из этих двух вариантов, то это будет автоматом означать, что ты просто обычный форумный болтун, на которого нет никакого смысла тратить время.
Re[8]: Facebook и язык D - первый шаг наверх.
От: alex_public  
Дата: 10.11.13 14:12
Оценка:
Здравствуйте, gandjustas, Вы писали:

_>>С учётом того, на чём написаны сами .net, mono, java, эта фраза звучит особенно пикантно. Видимо здесь присутствует какая-то магия. )))

G>Это тебе помогает писать код? Какая разница на чем рантайм написан, если ты прикладные вещи пишешь?

Ууу снова отмазки пошли. В твоём сообщение то была фраза: "Сейчас спектр систем, где заработает код на C#, примерно такой же, как у java и у обоих гораздо шире, чем у C++". Т.е. подразумевается, что есть ОС где C# или java код запустится, а C/C++ нет.
Re[27]: Facebook и язык D - первый шаг наверх.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.11.13 14:16
Оценка: +1
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, gandjustas, Вы писали:


G>>А какой тогда смысл в асинхронности вообще? Запусти в отдельном потоке и радуйся.


_>Да, это как раз самое лучшее решение (для работы с блокирующим кодом). Но оно далеко не всегда возможно. Проблема в том (на нашем примере), что ComplexFunction нельзя выполнять в отдельном потоке, а можно только в ui.

Ну сделай маршалинг UI вызовов, это все равно будет эффективнее создания кучи потоков.


G>>Без асинхронного IO бесполезная тема. А тебя единственный способ превращения синхронного в асинхронный — создание потока. Я и предлагаю не мучать жопу с корутинами, а сразу на потоках построить.

_>Да, можно. Опять же переписав сложную библиотечную функцию...
У тебя же есть исходники, иначе как ты узнаешь какие методы надо переопределять?


G>>Но Async\await умеет и в рамках нескольких потоков работать и с async io, а Boost.Coroutine — увы

G>>Так что несимметричная.
_>Как раз Boost.Coroutine только в рамках одного потока и работает. Это я её раскидал на несколько с помощью своего кода.
А ты попробуй написать так, чтобы вообще без доп потоков. Иначе смысл твоего переписывания теряется.

G>>

G>>Она только тебе интересно, потому что другие случаи ты сделать не сможешь.

_>Не могу? )))

Конечно не можешь. Потому что надо научиться комбинировать асинхронные вызовы и масштабировать это все.

Да_> это же ещё проще чем вариант с потоками. Ну смотри, будет тебе вторая задачка... И так берём этот http://www.rsdn.ru/forum/philosophy/5357968
Автор: alex_public
Дата: 09.11.13
же пример и меняем там пункт 3 на:


_>
_> /*skipped*/
_>

Поздравляю, ты осилил асинхронный IO. Теперь попробуй научиться комбинировать асинхронные вызовы.
Например у тебя идет подряд два чтения — одно из файла, другое из сети, нет смысла дожидаться завершения первого, чтобы запустить второе. Можно запустить их параллельно, а потом вернуться как оба закончатся.
Осилишь такое с корутинами?

Вот пример на C#

Было
var len1 = network.Read(buf1,0, buf1.Length);
var len2 = file.Read(buf2,0, buf2.Length);
someF(buf1,len1, buf2, len2)


Стало
var result = await Task.WhenAll(network.ReadAsync(buf1,0, buf1.Length),file.ReadAsync(buf2,0, buf2.Length));
someF(buf1,result[0], buf2, result[1])


Ограничений никаких нет.





G>>На практике как раз самое интересное — асинхронный IO и масштабирование.

G>>Если у тебя IO должен быть синхронный (странно почему, Windows поддерживает IOCP с тех пор когда буста еще не было), то просто делаешь потоки. Но у тебя наступает вполне резонная жопа с масштабируемостью.

_>Ещё раз, описываемые тобой проблемы с многопоточным вариантом актуальны только для специфической области типа написания высоконагруженных серверов.

Наверное поэтому весь IO в WinRT сделали асинхронным

_>И если уж мы говорим о ней и нам критично быстродействие, то C# await/async тоже не стоит применять.

С чего ты это взял?
Re[29]: Facebook и язык D - первый шаг наверх.
От: artelk  
Дата: 10.11.13 14:53
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, artelk, Вы писали:


A>>Не будет ли проблемы?


EP>Нет — эти сопроцедуры работают в одном потоке.


def download_and_update_statistics(url):
    x = statistics
    y = download_and_calculate_statistics(url)
    statistics =  x + y


Не будет ли проблемы?

EP>Проблемы с внешнем кодом могут быть если внутри есть что-то типа:

EP>
EP>// must happen atomically
EP>{
EP>    half_modify(structure);
EP>    stream >> x;
EP>    finish_modification(structure);
EP>}
EP>
В этом случае если внутри "stream >> x" произойдёт yield, то инварианты могут быть поломаны. Но, если есть такой код — то ты его и на обычных потоках не сможешь запустить, корутины тут не причём


Т.е. вот так взять и сделать произвольный синхронный код асинхронным,при этом не смотря в него, нельзя.
Фишка в том, что автор этого "произвольного кода" ничего не знает о том, что в вызывающей стороне делаются хаки и игры со стеком, и в следующей версии функций может поломать инварианты. Не, лучше явный async\await...
Re[31]: Facebook и язык D - первый шаг наверх.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.11.13 15:04
Оценка: :)))
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, gandjustas, Вы писали:


EP>>>std::getline тут стандартная, не модифицированная. Точно также можно протащить yield и через любую другую функцию

G>>Да, вот только надо очень хорошо понимать как работает эта функция. К счастью для переписывания синхронного кода в асинхронный в .NET не надо разбираться как он внтури устроен. Можно просто базвоые методы, которые делают IO сделать async, а дальше следуя руганиям компилятора добавить async\await во все методы выше по цепочке вызовов.

EP>В цепочке вызовов находится код исходников которого нет, что теперь?

В .NET очень легко — берешь dll и достаешь исходники.
В С++ — хз что делать, даже твой способ нельзя применять, ибо гарантий никаких.


EP>>>>>Что значит особый случай? Точно также можно завернуть tcp_stream.

G>>>>Надо очень хорошо знать как код работает внутри, чтобы делать такую асинхронность.
EP>>>Есть любая асинхронная функция которая принимает continuation/.then — мы ей передаём в этот continuation код с yield-ом внутри, что механически превращает остаток нашей функции в продолжение.
G>>Пример давай.

EP>Пример.
Автор: Evgeny.Panasyuk
Дата: 27.06.13


Понял, но тогда композицию не сделаешь. Вся соль продолжений что их можно комбинировать, цепочку продолжений сделать или fork\join.

Но только как это относится к случаю когда есть код, о котором ты не знаешь вообще ничего? lib или dll с сишным интерфейом (каковых подавляющее большинство).

G>>>>А как комбинировать такие асинхронные вызовы не то что не очевидно, а вообще непонятно как.

EP>>>Ты о чём?
G>>Напрмиер так:
G>>у тебя есть асинхронные функции f1 и f2, внтури они делают какой-то IO. Тебе нужно написать функцию f3, которая вызывает f1 и f2 параллельно, ждет их завершения и вызывает асинхронную операцию.
G>>Реальное применение такой функции — сервис поиска авиабилетов. Он обращается параллельно к десяткам перевозчиков, получает данные, выбирает лучшие варианты, отдает клиентам. Естественно это hiload сервис, который не может позволить себе создавать потоки.

EP>То есть ты мой пример
Автор: Evgeny.Panasyuk
Дата: 03.07.13
не смотрел?

Смотрел, в том числе github и нашел там такой код:

    Task task;
    while(!finished)
    {
        main_tasks.pop(task);
        task();
    }


Это сразу же ставит крест на серверных решениях и масштабируемости вообще.
А на клиенте проще отдельный поток запустить для операций, и маршалить вызовы в UI.


EP>>>>>При этом код использующий этот поток не поменяется, а в случае с C# await — нужно будет патчить весь call-stack

G>>>>А зачем это делать? Преобразование синхронного кода в асинхронный — механическая операция, легко автоматизируется при желании. Я даже для стримов на roslyn такое переписывание делал.
EP>>>С такими же рассуждениями можно прийти к мысли что и yield, и await/async не нужны
G>>Практика то показывает что нужны. Причем тут рассуждения?

EP>Ну ты говоришь что преобразование синхронного кода в асинхронный это механическая операция. Так и преобразование кода с await/yield — точно такая же механическая операция

Во-первых это не так из-за message pump.
Во-вторых ты утверждал что надо патчить call-stack. Я выделил твое утверждение.

G>>То что ты считаешь что нужно патчить call-stack — вывод, основанный на неверной посылке.

EP>Подробнее.
В .NET нет смысла хранить callstack, потому что нету деструкторов, поэтому очень легко делать продолжения. В C++ тебе нужен callstack для освобождения ресурсов, вот ты и думаешь что он является необходимостью.

Аналог твоего кода на github для .NET еще в 2008 году писал Richter:
http://msdn.microsoft.com/ru-ru/magazine/cc546608.aspx

Тогда еще не было async\await. В .NET с версии 2.0 есть итераторы, которые явлются частным случаем корутин, которые в свою очередь являются частным случаем продолжений.
Чувак на итераторах изобрел что-то вроде локальных асинхронных корутин, и там совсем не требовались игры с callstack.
Это то, к чему вы с alex_public мееедленно ползете.





EP>>>Как это никто не сделал? Раз, два, да даже возьми хоть мой пример реализации await
Автор: Evgeny.Panasyuk
Дата: 03.07.13
(это при том что я сам практически не работаю ни с каким io).

G>>Без асинхронного IO это все смысла не имеет. Покажи пример с асинхронным IO.

EP>Слушай, ну если ты не нацелен на конструктив, давай прекратим, ок? По второй ссылке Boost.Asio — самое что ни на есть асинхронное I/O, с тем самым IOCP под капотом

И как это комбинировать? Как запустить два параллельных считывания?


G>>>>Для начала тебе надо будет async io реализовать на IOCP.

EP>>>Ты мне предлагаешь реализовать свои обвёртки поверх голого IOCP? Зачем?
G>>Без асинхронного IO все что ты пишешь не имеет смысла. Вообще.
EP>Подожди, то есть ты думаешь что для C++ нет библиотек асинхронным API
Кроме буст? Увы очень мало и плохо работает.


G>>Ты вообще представляешь как медленно будет работать твой пример с getline на реальном файле?

G>>Опубликуешь результаты забегов? При этом масштабирования такой подход не добавил. Ты не сможешь также запустить 100500 чтений файлов и выйграть хоть что-то.
EP>getline может читать из любого стрима, например из сокета. В одном потоке будут крутится тысячи потоков с getline внутри, который ничего не знает об корутинах.
И что? Все равно то, что ты показал будет тормозить. Скорее всего аццки тормозить.



EP>>>О том, что для того чтобы сделать yield с самого низа callstack'а на самый вверх, тебе придётся дублировать и модифицировать каждый уровень. Причём эти уровни могут находится в библиотеках к которым нет доступа.

G>>В смысле "нет доступа" ?
G>>Если библиотеки — "черный ящик", то и твой подход не поможет, потому что требует знать как внутри работа устроена.
G>>Если у тебя таки есть доступ к исходникам, то кто мешает сделать ctrl+c-ctrl+v и добавить async\await?

EP>Детский сад — для того чтобы пользоваться библиотекой знать её код не обязательно. В нормальных библиотеках есть чётко определённый интерфес

И что? Как ты гарантируешь что инварианты не поломаются?
Твой пример базируется на том что у тебя функция — прозрачный ящик. В этом случае я просто скопирую код и сделаю его async.


EP>>>У тебя нет кода std::getline (или аналога) — куда ты там собрался дописывать await?

G>>Если тебя нет когда getline, то как ты написал свой код? Он же полностью базируется на знании устройства getline, значит код у тебя есть.
EP>Это привязка не к устройству, а к интерфейсу
Именно к устройству, потому что иначе гарантий никаких.
Re[28]: Facebook и язык D - первый шаг наверх.
От: alex_public  
Дата: 10.11.13 15:54
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Ну сделай маршалинг UI вызовов, это все равно будет эффективнее создания кучи потоков.


У тебя какая-то паранойя с потоками. В не северных ситуаций они очень даже эффективны. Тем более, если учесть текущие тенденции в развитие процессоров...

G>У тебя же есть исходники, иначе как ты узнаешь какие методы надо переопределять?


У меня заголовочные файлы и скомпилированные lib/dll файлы. Многие библиотеки распространяются именно так. Но даже если бы и были исходники. Я не собираюсь переписывать кучи чужих библиотек, если этого можно не делать. И это возможно, в C++, но не в .net.

G>Поздравляю, ты осилил асинхронный IO. Теперь попробуй научиться комбинировать асинхронные вызовы.

G>Например у тебя идет подряд два чтения — одно из файла, другое из сети, нет смысла дожидаться завершения первого, чтобы запустить второе. Можно запустить их параллельно, а потом вернуться как оба закончатся.
G>Осилишь такое с корутинами?

G>Вот пример на C#


G>Было

G>
G>var len1 = network.Read(buf1,0, buf1.Length);
G>var len2 = file.Read(buf2,0, buf2.Length);
G>someF(buf1,len1, buf2, len2)
G>


G>Стало

G>
G>var result = await Task.WhenAll(network.ReadAsync(buf1,0, buf1.Length),file.ReadAsync(buf2,0, buf2.Length));
G>someF(buf1,result[0], buf2, result[1])
G>


G>Ограничений никаких нет.


А в чём проблема то в этой простейшей задачке? ) Синхронный код:
vector<char> buf1, buf2;
network.Read(buf1);
file.Read(buf2);
F(buf1, buf2);
Асинхронный код:
vector<char> buf1, buf2;
int c=2;
network.StartAsyncRead(buf1, [&]{if(--c==0) CallFromUI(__coro);});
file.StartAsyncRead(buf2, [&]{if(--c==0) CallFromUI(__coro);});
__yield();
F(buf1, buf2);
Это так сказать внутренности. Как ты понимаешь, это всё без проблем упаковывается в симпатичный макрос, который делает всё автоматически и даже будет красивее твоего вариант. Но я это не стал делать, т.к. ты бы тогда наверняка тут же придрался и потребовал показать внутренности макроса.

_>>И если уж мы говорим о ней и нам критично быстродействие, то C# await/async тоже не стоит применять.

G>С чего ты это взял?

Потому что этот синтаксический сахар не является бесплатным по накладным ресурсам.

P.S. Пока ещё жду твоего ответа на моё предыдущее сообщение...
Re[33]: Facebook и язык D - первый шаг наверх.
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.11.13 19:37
Оценка: -1 :)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Ещё раз. Я озвучил факт, который оппонент не знал/не понимал.


Ты сам себе придумал, что ктото чего то не понимает.

>Что с этого? Ну как минимум теперь он знает


Ога.

EP>Вот ты тоже не знал, не верил, отрицал. Зато теперь "И что с того ?" — большой прогресс


Если тебя подводит память, то я напомню — ты утверждал, что асинхронщину не надо всовывать в эвентлуп. И доказал это утверждение кодом в котором всунул асинхронщину в WM_CHAR.
Re[35]: Facebook и язык D - первый шаг наверх.
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.11.13 19:39
Оценка: :)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

I>>Вот такие фокусы и в джаве, и в дотнете, и в питоне.


EP>Откуда именно тут coroutine, покажи полный код на C#.


Из либы. Зачем тебе код ?
Re[23]: Facebook и язык D - первый шаг наверх.
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.11.13 19:41
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, Ikemefula, Вы писали:


I>>Всё в один поток не всунешь. Нужен инструмент, который дает единообразный код независимо от диспетчеризации. Если винда не умеет чего то диспетчеризовать в какой то поток, это ничего не меняет. Пишешь диспетчер и все дела — сам код каким был, таким и остался.


_>Причём тут в один поток? Здесь речь не о запуске нового потока, а об исполнение продолжения в новом. Хотя инициации запуска была уже не в ui потоке (который мы там как-то ещё уже запустили). Смысла у этого особо не видно.


Смысл простой — есть результаты, которые нужны сразу, и на них требование например время отклика ограничено. А остальные могут и подождать. Эта задача, к слову, встречается не только в UI.
Re[31]: Facebook и язык D - первый шаг наверх.
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.11.13 19:46
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

G>>Да и в общем случае сделать из синхронного черного ящика асинхронный нельзя, потому что нет гарантии не нарушения инвариантов.


EP>Придумай хотя бы пару примеров поломки инвариантов в функции которая принимает пользовательский stream, и гарантированно работает в многопоточной среде.


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

Ты не можешь заранее сказать, что будет выполняться в тот момент, когда одна из нитей вызывает getline. Что будет если вторая нить вызовет тот же getline, скажем по какому нибудь эвенту и тд ?

В синхронном коде это не составит проблемы — понадобился ввод, пиши getline и все дела. А с твоими короутинами надо отслеживать руками, что же может выполняться в нити и у тебя нет никакого ограничивающего контекста.
Re[25]: Facebook и язык D - первый шаг наверх.
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.11.13 19:59
Оценка:
Здравствуйте, alex_public, Вы писали:

I>>Опаньки ! "переписывать надо исключительно из-за особенностей реализации await/async в .net"

I>>И одновременно, оказывается, дотнет ни при чем, а всё зависит от особенностей реализации. Браво !

_>Не, не так. Есть функции которые можно преобразовать в асинхронные без переписывания, а есть такие, которые нельзя. А вот .net заставляет нас переписывать любые, т.к. требует раскидывания async по всему стеку вызова.


И это правильно ! Ты не думал, почему аналогичные структуры хотят ввести в стандарт С++ ?

_>Я хотел сказать, что и в .net и в C++ модель await/async в общем то не так уж и нужна. ))) По сути это сахар на достаточно специфическую ситуацию. Собственно мы это уже обсуждали в той старой темке.


Наоборот — именно этот механизм и нужен для асинхронщины. Просто по той простой причине, что асинхронная многозадачность на порядок сложнее обычной скажем многопоточной многозадачности. В ней нет никакого ограничивающего контекста. Соответственно любая локальная задача превращается в глобальную проблему.

Потому и нужен механизм, который позволит решать такие проблемы локально, а не неявно модифицировать поведение непойми каких функций.

I>>И получаешь нарушение инварианта.


_>С чего бы это? Там выполнение будет строго последовательным, просто разделённым на два потока.


Cам подумай:

// Вот код, с которым все шоколадно в синхронном однопоточном коде
value = read()
write(next(value))

// а вот однопоточныый вариант, но асинхронный
нить 1 value = read()
нить 2 value = read()
нить 2 write(next(value)) 
нить 1 write(next(value)) // нарушение инварианта

// и вот
нить 1 value = read()
нить 2 value = read()
нить 1 write(next(value))
нить 2 write(next(value)) // нарушение инварианта
Re[29]: Facebook и язык D - первый шаг наверх.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.11.13 22:49
Оценка: :)
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, gandjustas, Вы писали:


G>>Ну сделай маршалинг UI вызовов, это все равно будет эффективнее создания кучи потоков.


_>У тебя какая-то паранойя с потоками. В не северных ситуаций они очень даже эффективны. Тем более, если учесть текущие тенденции в развитие процессоров...


Для клиента я пишу на JS, там однопоточная асинхронность. На сервере — async\await самое то.
Это как раз к тому, что потоки, особенно созданные вручную, почти не нужны, если у тебя есть нормальный асинронный IO.

G>>У тебя же есть исходники, иначе как ты узнаешь какие методы надо переопределять?


_>У меня заголовочные файлы и скомпилированные lib/dll файлы. Многие библиотеки распространяются именно так. Но даже если бы и были исходники. Я не собираюсь переписывать кучи чужих библиотек, если этого можно не делать. И это возможно, в C++, но не в .net.

Да и в C++ в общем случае невозможно. Инварианты посыпятся в любом нетривиальном коде. А тривиальный можно и переписать.

Кстати в .NET тоже вполне возможно:
Вот функция:
static void ComplexFunc(Stream src, Stream dst)
{
    var buf = new byte[256];
    while(src.Position < src.Length)
    {
        var len = src.Read(buf,0,buf.Length);
        dst.Write(buf, 0, len);
    }
}

Примитивное копирование потока.

Вот эвентхендлер:

private void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 100; i++)
    {
        using (var src = File.OpenRead("TextFile1.txt"))
        using (var dst = File.Create("TextFile2.txt"))
            ComplexFunc(src, dst);
        Console.WriteLine("Iteration " + i);
    }
}


Вот он-же в криво-асинхронном варианте:

private void button1_Click(object sender, EventArgs e)
{
    scheduler.CreateFiber((s, yield) => { 
        for (int i = 0; i < 100; i++)
        {
            using (var src = new AsyncStream(File.OpenRead("TextFile1.txt"), yield))
            using (var dst = new AsyncStream(File.Create("TextFile2.txt"), yield))
                ComplexFunc(src, dst);
            Console.WriteLine("Iteration " + i);
        }
    });
}


Реализация AsyncStream (значимые части):

class AsyncStream:Stream
{
    Stream baseStream;
    Action<bool> yield;

    public AsyncStream(Stream baseStream, Action<bool> yield)
    {
        this.baseStream = baseStream;
        this.yield = yield;
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        var task = baseStream.ReadAsync(buffer, offset, count);

        task.GetAwaiter().OnCompleted(() => yield(true));
        yield(false);
        return task.Result;            
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        var task = baseStream.WriteAsync(buffer, offset, count);
        task.GetAwaiter().OnCompleted(() => yield(true));
        yield(false);
        return;
    }
}

Заметь, никаких потоков, await просто руками написал. IO делается асинхронно за счет IOCP.

Код шедулера:
  Скрытый текст
public class FiberScheduler
{
    private ConcurrentQueue<Fiber> queue = new ConcurrentQueue<Fiber>();

    public uint PrimaryId { get; private set; }


    public FiberScheduler()
    {
        this.PrimaryId = UnmanagedFiberAPI.ConvertThreadToFiber(0);
        if (this.PrimaryId == 0)
        {
            throw new Win32Exception();
        }
    }

    public Fiber CreateFiber(Action<FiberScheduler, Action<bool>> action)
    {
        var fiber = new Fiber(action, this);
        queue.Enqueue(fiber);
        return fiber;
    }

    public void Delete(Fiber fiber)
    {
        fiber.Delete();
        UnmanagedFiberAPI.DeleteFiber(fiber.Id);
            
    }

    internal void Switch(Fiber fib, bool enqueue)
    {
        if (enqueue)
        {
            queue.Enqueue(fib);
        }
        UnmanagedFiberAPI.SwitchToFiber(this.PrimaryId);
    }

    public void Next()
    {
        Fiber fib;
        if (queue.TryDequeue(out fib))
        {
            switch (fib.Status)
            {
                case FiberStatus.Error:
                case FiberStatus.Started:
                case FiberStatus.Done:
                    UnmanagedFiberAPI.SwitchToFiber(fib.Id);
                    break;
                default:
                    break;
            }
        }
    }
}


Вспомогательные классы:
  Скрытый текст
public enum FiberStatus
{
    Error,
    Started,
    Done,
    Deleted
}
public class Fiber
{
    private Action<FiberScheduler, Action<bool>> action;

    public uint Id { get; private set; }

    public FiberScheduler Scheduler { get; private set; }

    public FiberStatus Status { get; internal set; }


    internal Fiber(Action<FiberScheduler, Action<bool>> action, FiberScheduler scheduler)
    {
        this.action = action;

        Scheduler = scheduler;
        Status = FiberStatus.Started;

        UnmanagedFiberAPI.LPFIBER_START_ROUTINE lpFiber = new UnmanagedFiberAPI.LPFIBER_START_ROUTINE(FiberRunnerProc);
        Id = UnmanagedFiberAPI.CreateFiber(0, lpFiber, 0);

        if(Id == 0)
        {
            throw new Win32Exception();
        }
    }

    private uint FiberRunnerProc(uint lpParam)
    {
        uint status = 0;
        try
        {
            action(this.Scheduler, Yield);
            Status = FiberStatus.Done;
        }

        catch (Exception)
        {
            status = 1;
            Status = FiberStatus.Error; 
            throw;
        }

        finally
        {
            Yield(false);
            UnmanagedFiberAPI.DeleteFiber((uint)Id);
            Status = FiberStatus.Deleted;
        }

        return status;
    }

    private void Yield(bool enqueue)
    {
        this.Scheduler.Switch(this, enqueue);
            
    }

    internal void Delete()
    {
        this.Status = FiberStatus.Deleted;            
    }
}

internal static class UnmanagedFiberAPI
{
    public delegate uint LPFIBER_START_ROUTINE(uint param);

    [DllImport("Kernel32.dll")]
    public static extern uint ConvertThreadToFiber(uint lpParameter);

    [DllImport("Kernel32.dll")]
    public static extern void SwitchToFiber(uint lpFiber);

    [DllImport("Kernel32.dll")]
    public static extern void DeleteFiber(uint lpFiber);

    [DllImport("Kernel32.dll")]
    public static extern uint CreateFiber(uint dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, uint lpParameter);
}


Но со сложным кодом в complexdunc такое сделать не выйдет, .NET начнет бить тревогу.
Аналогично любой сложный библиотечный код поломается если ему вместо синхронной реализации подсунуть хрен-пойми-какую.
Гораздо проще в .NET вытащить async api. В C++ покачто с async api проблемы, может в C++14 починят.

G>>Поздравляю, ты осилил асинхронный IO. Теперь попробуй научиться комбинировать асинхронные вызовы.

G>>Например у тебя идет подряд два чтения — одно из файла, другое из сети, нет смысла дожидаться завершения первого, чтобы запустить второе. Можно запустить их параллельно, а потом вернуться как оба закончатся.
G>>Осилишь такое с корутинами?

_>А в чём проблема то в этой простейшей задачке? ) Синхронный код:

_>
_>vector<char> buf1, buf2;
_>network.Read(buf1);
_>file.Read(buf2);
_>F(buf1, buf2);
_>
Асинхронный код:

_>
_>vector<char> buf1, buf2;
_>int c=2;
_>network.StartAsyncRead(buf1, [&]{if(--c==0) CallFromUI(__coro);});
_>file.StartAsyncRead(buf2, [&]{if(--c==0) CallFromUI(__coro);});
_>__yield();
_>F(buf1, buf2);
_>
Это так сказать внутренности. Как ты понимаешь, это всё без проблем упаковывается в симпатичный макрос, который делает всё автоматически и даже будет красивее твоего вариант. Но я это не стал делать, т.к. ты бы тогда наверняка тут же придрался и потребовал показать внутренности макроса.

Поздравляю, ты изобрел асинхронные корутины. Их для .NET Рихтер изобрел в 2007 году
Но у тебя как обычно несколько проблемы:
1) нужен message pump для корутин, обязательно однопоточный.
2) Нужен message pump для асинхронного IO, тут уже зависит от реализации.
3) Все это дико тормозит без возможности улучшения (потому что 1 и 2).

_>>>И если уж мы говорим о ней и нам критично быстродействие, то C# await/async тоже не стоит применять.

G>>С чего ты это взял?

_>Потому что этот синтаксический сахар не является бесплатным по накладным ресурсам.



PS. Времени нет на все отвечать
Re[30]: Facebook и язык D - первый шаг наверх.
От: Evgeny.Panasyuk Россия  
Дата: 11.11.13 00:37
Оценка:
Здравствуйте, artelk, Вы писали:

A>>>Не будет ли проблемы?

EP>>Нет — эти сопроцедуры работают в одном потоке.
A>
A>def download_and_update_statistics(url):
A>    x = statistics
A>    y = download_and_calculate_statistics(url)
A>    statistics =  x + y
A>

A>Не будет ли проблемы?

Тут проблема будет даже и с обычными потоками — download_and_update_statistics не thread safe

EP>>Проблемы с внешнем кодом могут быть если внутри есть что-то типа:

EP>>
EP>>// must happen atomically
EP>>{
EP>>    half_modify(structure);
EP>>    stream >> x;
EP>>    finish_modification(structure);
EP>>}
EP>>
В этом случае если внутри "stream >> x" произойдёт yield, то инварианты могут быть поломаны. Но, если есть такой код — то ты его и на обычных потоках не сможешь запустить, корутины тут не причём

A>Т.е. вот так взять и сделать произвольный синхронный код асинхронным,при этом не смотря в него, нельзя.
A>Фишка в том, что автор этого "произвольного кода" ничего не знает о том, что в вызывающей стороне делаются хаки и игры со стеком, и в следующей версии функций может поломать инварианты. Не, лучше явный async\await...

Давай примеры:

Придумай хотя бы пару примеров поломки инвариантов в функции которая принимает пользовательский stream, и гарантированно работает в многопоточной среде.

Re[32]: Facebook и язык D - первый шаг наверх.
От: Evgeny.Panasyuk Россия  
Дата: 11.11.13 00:54
Оценка:
Здравствуйте, gandjustas, Вы писали:


EP>>>>std::getline тут стандартная, не модифицированная. Точно также можно протащить yield и через любую другую функцию

G>>>Да, вот только надо очень хорошо понимать как работает эта функция. К счастью для переписывания синхронного кода в асинхронный в .NET не надо разбираться как он внтури устроен. Можно просто базвоые методы, которые делают IO сделать async, а дальше следуя руганиям компилятора добавить async\await во все методы выше по цепочке вызовов.
EP>>В цепочке вызовов находится код исходников которого нет, что теперь?
G>В .NET очень легко — берешь dll и достаешь исходники.

Отличный способ

G>В С++ — хз что делать, даже твой способ нельзя применять, ибо гарантий никаких.


И тем не менее пример ты не привёл
Автор: Evgeny.Panasyuk
Дата: 10.11.13
.

EP>>>>>>Что значит особый случай? Точно также можно завернуть tcp_stream.

G>>>>>Надо очень хорошо знать как код работает внутри, чтобы делать такую асинхронность.
EP>>>>Есть любая асинхронная функция которая принимает continuation/.then — мы ей передаём в этот continuation код с yield-ом внутри, что механически превращает остаток нашей функции в продолжение.
G>>>Пример давай.
EP>>Пример.
Автор: Evgeny.Panasyuk
Дата: 27.06.13

G>Понял, но тогда композицию не сделаешь. Вся соль продолжений что их можно комбинировать, цепочку продолжений сделать или fork\join.

Я уже показывал пример комбинирования:
for(auto &&f : fs)
    cout << await f << ":\tafter end" << endl;
// or
await when_all(fs);


EP>>То есть ты мой пример
Автор: Evgeny.Panasyuk
Дата: 03.07.13
не смотрел?

G>Смотрел, в том числе github и нашел там такой код:
G>
G>    Task task;
G>    while(!finished)
G>    {
G>        main_tasks.pop(task);
G>        task();
G>    }
G>


И комментарий ты тоже прочитал?
    // Custom scheduling is not required - can be integrated
    // to other systems transparently
    main_tasks.push([]
    {
        asynchronous([]
        {
            return async_user_handler(),
                   finished = true;
        });
    });

    Task task;
    while(!finished)
    {
        main_tasks.pop(task);
        task();
    }


G>Это сразу же ставит крест на серверных решениях и масштабируемости вообще.


Почему? Такой подход спокойно работает с Boost.Asio — хватит уже чушь нести.

EP>>Ну ты говоришь что преобразование синхронного кода в асинхронный это механическая операция. Так и преобразование кода с await/yield — точно такая же механическая операция

G>Во-первых это не так из-за message pump.

Какого message pump? Вот пример
Автор: Evgeny.Panasyuk
Дата: 29.06.13
полностью локальной трансформации:
// было:
void task()
{
    MessageBox(0, TEXT("on max"), TEXT(""), MB_OK);
    async_something([]
    {
        MessageBox(0, TEXT("on min"), TEXT(""), MB_OK);
    });
}
// стало:
void task()
{
    // without syntax sugar
    typedef boost::coroutines::coroutine<void()> Coro;
    auto &&red_portal = make_shared<Coro>();
    *red_portal = Coro([=](Coro::caller_type &blue_portal)
    {
        MessageBox(0, TEXT("on max"), TEXT(""), MB_OK);
        async_something( [=]{ (*red_portal)(); } );
        blue_portal();
        MessageBox(0, TEXT("on min"), TEXT(""), MB_OK);
    });
}


G>Во-вторых ты утверждал что надо патчить call-stack. Я выделил твое утверждение.


Ну так ты же и говоришь, что тебе нужно доставать исходники:

G>В .NET очень легко — берешь dll и достаешь исходники.

чтобы проставить await'ы

G>>>То что ты считаешь что нужно патчить call-stack — вывод, основанный на неверной посылке.

EP>>Подробнее.
G>В .NET нет смысла хранить callstack, потому что нету деструкторов, поэтому очень легко делать продолжения. В C++ тебе нужен callstack для освобождения ресурсов, вот ты и думаешь что он является необходимостью.

G>Аналог твоего кода на github для .NET еще в 2008 году писал Richter:

G>http://msdn.microsoft.com/ru-ru/magazine/cc546608.aspx

И где там аналог? Там те же самые примитивные одноуровневые stackless coroutine что и у await

EP>>>>Как это никто не сделал? Раз, два, да даже возьми хоть мой пример реализации await
Автор: Evgeny.Panasyuk
Дата: 03.07.13
(это при том что я сам практически не работаю ни с каким io).

G>>>Без асинхронного IO это все смысла не имеет. Покажи пример с асинхронным IO.
EP>>Слушай, ну если ты не нацелен на конструктив, давай прекратим, ок? По второй ссылке Boost.Asio — самое что ни на есть асинхронное I/O, с тем самым IOCP под капотом
G>И как это комбинировать? Как запустить два параллельных считывания?

Через boost::asio::spawn

G>>>Ты вообще представляешь как медленно будет работать твой пример с getline на реальном файле?

G>>>Опубликуешь результаты забегов? При этом масштабирования такой подход не добавил. Ты не сможешь также запустить 100500 чтений файлов и выйграть хоть что-то.
EP>>getline может читать из любого стрима, например из сокета. В одном потоке будут крутится тысячи потоков с getline внутри, который ничего не знает об корутинах.
G>И что? Все равно то, что ты показал будет тормозить. Скорее всего аццки тормозить.

Почему?
Re[21]: Facebook и язык D - первый шаг наверх.
От: jazzer Россия Skype: enerjazzer
Дата: 11.11.13 00:56
Оценка:
Здравствуйте, hi_octane, Вы писали:

J>>Пример Яху всем известен, правда? Пара маргиналов написали систему на маргинальном языке (лиспе) и свалили. Яху помучилась-помучилась и переписала все на мейнстримовом языке.


_>Пример яху как раз шикарен. Пара маргиналов на маргинальном языке внезапно! в ошмётки порвала многочисленных конкурентов на мэйнстримовых языках, за что и были были куплены яху. Тут бы уже задаться вопросом, а с чего бы им это удалось?! Но ты акцентируешь внимание на том что в яху не смогла ни самих маргиналов удержать, ни проект ими поднятый, выдаёшь это за некое преимущество мэйнстримовых языков


Перечитай мое сообщение еще раз, что ли Я даже не знаю, что тут еще сказать.

_>А мне кажется, то что менеджмент яху, в отличии от раннего гугла, не умел строить бизнес силами маргиналов, как раз и есть причина их быстрого слива по всем направлениям


О чем я и говорил в том сообщении, на которое ты отвечаешь
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[34]: Facebook и язык D - первый шаг наверх.
От: Evgeny.Panasyuk Россия  
Дата: 11.11.13 01:01
Оценка:
Здравствуйте, Ikemefula, Вы писали:

EP>>Ещё раз. Я озвучил факт, который оппонент не знал/не понимал.

I>Ты сам себе придумал, что ктото чего то не понимает.

Например gandjustas начинает петь ту же самую песню про message pump, которую ты пел летом
Автор: Evgeny.Panasyuk
Дата: 29.06.13
:

I>Ну значит UI Loop из моего примера вызовется чудом, например сканированием адресного пространства на предмет наличия ::GetMessage и ::TranslateMessage или, как вариант, короутина догадается WinMain вызвать.

Репертуар "Осень 2013":

EP>>Ну ты говоришь что преобразование синхронного кода в асинхронный это механическая операция. Так и преобразование кода с await/yield — точно такая же механическая операция
G>Во-первых это не так из-за message pump.


EP>>Вот ты тоже не знал, не верил, отрицал. Зато теперь "И что с того ?" — большой прогресс

I>Если тебя подводит память, то я напомню — ты утверждал, что асинхронщину не надо всовывать в эвентлуп. И доказал это утверждение кодом в котором всунул асинхронщину в WM_CHAR.

Опять двадцать пять
Автор: Evgeny.Panasyuk
Дата: 29.06.13
:
// было:
void task()
{
    MessageBox(0, TEXT("on max"), TEXT(""), MB_OK);
    async_something([]
    {
        MessageBox(0, TEXT("on min"), TEXT(""), MB_OK);
    });
}
// стало:
void task()
{
    // without syntax sugar
    typedef boost::coroutines::coroutine<void()> Coro;
    auto &&red_portal = make_shared<Coro>();
    *red_portal = Coro([=](Coro::caller_type &blue_portal)
    {
        MessageBox(0, TEXT("on max"), TEXT(""), MB_OK);
        async_something( [=]{ (*red_portal)(); } );
        blue_portal();
        MessageBox(0, TEXT("on min"), TEXT(""), MB_OK);
    });
}
Трансформация полностью локальная
Re[36]: Facebook и язык D - первый шаг наверх.
От: Evgeny.Panasyuk Россия  
Дата: 11.11.13 01:02
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>Вот такие фокусы и в джаве, и в дотнете, и в питоне.

EP>>Откуда именно тут coroutine, покажи полный код на C#.
I>Из либы. Зачем тебе код ?

Полный код примера.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.