Здравствуйте, gandjustas, Вы писали:
Pzz>>Моно — это пионерская поделка, годящаясь только на то, чтобы изготавливать пионерские поделки. Существенной проблемой при этом является то, что пионеры не в состоянии понять, что кроссплатформенные пионерские поделки надо тестировать на всех платформах, а не только на любимом компьютере разработчила. Поэтому даже для изготовления кроссплатформенных пионерских поделок моно не годится. А пионерские поделки под венду проще все же делать, используя родные для венды средства.
G>А что мешает протестировать моно на разных компьютерах?
Ничего не мешает, но пионеры этого не делают. Вероятно, им в голову не приходит то, что это необходимо делать, и что на разных компьютерах программа может вести себя по-разному.
G>Кстати я собирал в студии проект который взлете на mono. Я наверное что-то не так сделал.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Плохой пример чего? Ты о чём? matumba считал что Linux это C++
Плохой пример чего бы то ни было, кроме писания монолитных ядер юникс-подобных ОС. Ядро линуха очень похоже на другие подобные ядра, и очень мало похоже на какие-либо другие программы.
Здравствуйте, gandjustas, Вы писали:
G>Да и в общем случае сделать из синхронного черного ящика асинхронный нельзя, потому что нет гарантии не нарушения инвариантов.
Придумай хотя бы пару примеров поломки инвариантов в функции которая принимает пользовательский stream, и гарантированно работает в многопоточной среде.
Здравствуйте, 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
поправкой (вариант без ненавистных тебе потоков). И мы все признаём, что реализация на C# не слабее.
Если в последующих твоих сообщениях не будет одного из этих двух вариантов, то это будет автоматом означать, что ты просто обычный форумный болтун, на которого нет никакого смысла тратить время.
Здравствуйте, gandjustas, Вы писали:
_>>С учётом того, на чём написаны сами .net, mono, java, эта фраза звучит особенно пикантно. Видимо здесь присутствует какая-то магия. ))) G>Это тебе помогает писать код? Какая разница на чем рантайм написан, если ты прикладные вещи пишешь?
Ууу снова отмазки пошли. В твоём сообщение то была фраза: "Сейчас спектр систем, где заработает код на C#, примерно такой же, как у java и у обоих гораздо шире, чем у C++". Т.е. подразумевается, что есть ОС где C# или java код запустится, а C/C++ нет.
Здравствуйте, 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
Поздравляю, ты осилил асинхронный 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 тоже не стоит применять.
С чего ты это взял?
Здравствуйте, 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>
В этом случае если внутри "stream >> x" произойдёт yield, то инварианты могут быть поломаны. Но, если есть такой код — то ты его и на обычных потоках не сможешь запустить, корутины тут не причём
Т.е. вот так взять и сделать произвольный синхронный код асинхронным,при этом не смотря в него, нельзя.
Фишка в том, что автор этого "произвольного кода" ничего не знает о том, что в вызывающей стороне делаются хаки и игры со стеком, и в следующей версии функций может поломать инварианты. Не, лучше явный async\await...
Здравствуйте, 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>Пример.
Понял, но тогда композицию не сделаешь. Вся соль продолжений что их можно комбинировать, цепочку продолжений сделать или fork\join.
Но только как это относится к случаю когда есть код, о котором ты не знаешь вообще ничего? lib или dll с сишным интерфейом (каковых подавляющее большинство).
G>>>>А как комбинировать такие асинхронные вызовы не то что не очевидно, а вообще непонятно как. EP>>>Ты о чём? G>>Напрмиер так: G>>у тебя есть асинхронные функции f1 и f2, внтури они делают какой-то IO. Тебе нужно написать функцию f3, которая вызывает f1 и f2 параллельно, ждет их завершения и вызывает асинхронную операцию. G>>Реальное применение такой функции — сервис поиска авиабилетов. Он обращается параллельно к десяткам перевозчиков, получает данные, выбирает лучшие варианты, отдает клиентам. Естественно это hiload сервис, который не может позволить себе создавать потоки.
EP>То есть ты мой пример
Это сразу же ставит крест на серверных решениях и масштабируемости вообще.
А на клиенте проще отдельный поток запустить для операций, и маршалить вызовы в 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 для освобождения ресурсов, вот ты и думаешь что он является необходимостью.
Тогда еще не было async\await. В .NET с версии 2.0 есть итераторы, которые явлются частным случаем корутин, которые в свою очередь являются частным случаем продолжений.
Чувак на итераторах изобрел что-то вроде локальных асинхронных корутин, и там совсем не требовались игры с callstack.
Это то, к чему вы с alex_public мееедленно ползете.
(это при том что я сам практически не работаю ни с каким 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>Это привязка не к устройству, а к интерфейсу
Именно к устройству, потому что иначе гарантий никаких.
Здравствуйте, gandjustas, Вы писали:
G>Ну сделай маршалинг UI вызовов, это все равно будет эффективнее создания кучи потоков.
У тебя какая-то паранойя с потоками. В не северных ситуаций они очень даже эффективны. Тем более, если учесть текущие тенденции в развитие процессоров...
G>У тебя же есть исходники, иначе как ты узнаешь какие методы надо переопределять?
У меня заголовочные файлы и скомпилированные lib/dll файлы. Многие библиотеки распространяются именно так. Но даже если бы и были исходники. Я не собираюсь переписывать кучи чужих библиотек, если этого можно не делать. И это возможно, в C++, но не в .net.
G>Поздравляю, ты осилил асинхронный IO. Теперь попробуй научиться комбинировать асинхронные вызовы. G>Например у тебя идет подряд два чтения — одно из файла, другое из сети, нет смысла дожидаться завершения первого, чтобы запустить второе. Можно запустить их параллельно, а потом вернуться как оба закончатся. G>Осилишь такое с корутинами?
G>Вот пример на C#
G>Было G>
Это так сказать внутренности. Как ты понимаешь, это всё без проблем упаковывается в симпатичный макрос, который делает всё автоматически и даже будет красивее твоего вариант. Но я это не стал делать, т.к. ты бы тогда наверняка тут же придрался и потребовал показать внутренности макроса.
_>>И если уж мы говорим о ней и нам критично быстродействие, то C# await/async тоже не стоит применять. G>С чего ты это взял?
Потому что этот синтаксический сахар не является бесплатным по накладным ресурсам.
P.S. Пока ещё жду твоего ответа на моё предыдущее сообщение...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ещё раз. Я озвучил факт, который оппонент не знал/не понимал.
Ты сам себе придумал, что ктото чего то не понимает.
>Что с этого? Ну как минимум теперь он знает
Ога.
EP>Вот ты тоже не знал, не верил, отрицал. Зато теперь "И что с того ?" — большой прогресс
Если тебя подводит память, то я напомню — ты утверждал, что асинхронщину не надо всовывать в эвентлуп. И доказал это утверждение кодом в котором всунул асинхронщину в WM_CHAR.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Вот такие фокусы и в джаве, и в дотнете, и в питоне.
EP>Откуда именно тут coroutine, покажи полный код на C#.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Всё в один поток не всунешь. Нужен инструмент, который дает единообразный код независимо от диспетчеризации. Если винда не умеет чего то диспетчеризовать в какой то поток, это ничего не меняет. Пишешь диспетчер и все дела — сам код каким был, таким и остался.
_>Причём тут в один поток? Здесь речь не о запуске нового потока, а об исполнение продолжения в новом. Хотя инициации запуска была уже не в ui потоке (который мы там как-то ещё уже запустили). Смысла у этого особо не видно.
Смысл простой — есть результаты, которые нужны сразу, и на них требование например время отклика ограничено. А остальные могут и подождать. Эта задача, к слову, встречается не только в UI.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
G>>Да и в общем случае сделать из синхронного черного ящика асинхронный нельзя, потому что нет гарантии не нарушения инвариантов.
EP>Придумай хотя бы пару примеров поломки инвариантов в функции которая принимает пользовательский stream, и гарантированно работает в многопоточной среде.
А почему инварианты должны ломаться именно в этой функции ? Ты хочешь решить локальную проблему, глобальным механизмом. Соответсвенно инварианты будут ломаться так же глобально.
Ты не можешь заранее сказать, что будет выполняться в тот момент, когда одна из нитей вызывает getline. Что будет если вторая нить вызовет тот же getline, скажем по какому нибудь эвенту и тд ?
В синхронном коде это не составит проблемы — понадобился ввод, пиши getline и все дела. А с твоими короутинами надо отслеживать руками, что же может выполняться в нити и у тебя нет никакого ограничивающего контекста.
Здравствуйте, 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)) // нарушение инварианта
Здравствуйте, 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>>Осилишь такое с корутинами? _>А в чём проблема то в этой простейшей задачке? ) Синхронный код: _>
Это так сказать внутренности. Как ты понимаешь, это всё без проблем упаковывается в симпатичный макрос, который делает всё автоматически и даже будет красивее твоего вариант. Но я это не стал делать, т.к. ты бы тогда наверняка тут же придрался и потребовал показать внутренности макроса.
Поздравляю, ты изобрел асинхронные корутины. Их для .NET Рихтер изобрел в 2007 году
Но у тебя как обычно несколько проблемы:
1) нужен message pump для корутин, обязательно однопоточный.
2) Нужен message pump для асинхронного IO, тут уже зависит от реализации.
3) Все это дико тормозит без возможности улучшения (потому что 1 и 2). _>>>И если уж мы говорим о ней и нам критично быстродействие, то C# await/async тоже не стоит применять. G>>С чего ты это взял? _>Потому что этот синтаксический сахар не является бесплатным по накладным ресурсам.
Здравствуйте, 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>>
В этом случае если внутри "stream >> x" произойдёт yield, то инварианты могут быть поломаны. Но, если есть такой код — то ты его и на обычных потоках не сможешь запустить, корутины тут не причём A>Т.е. вот так взять и сделать произвольный синхронный код асинхронным,при этом не смотря в него, нельзя. A>Фишка в том, что автор этого "произвольного кода" ничего не знает о том, что в вызывающей стороне делаются хаки и игры со стеком, и в следующей версии функций может поломать инварианты. Не, лучше явный async\await...
Давай примеры:
Придумай хотя бы пару примеров поломки инвариантов в функции которая принимает пользовательский stream, и гарантированно работает в многопоточной среде.
EP>>>>std::getline тут стандартная, не модифицированная. Точно также можно протащить yield и через любую другую функцию G>>>Да, вот только надо очень хорошо понимать как работает эта функция. К счастью для переписывания синхронного кода в асинхронный в .NET не надо разбираться как он внтури устроен. Можно просто базвоые методы, которые делают IO сделать async, а дальше следуя руганиям компилятора добавить async\await во все методы выше по цепочке вызовов. EP>>В цепочке вызовов находится код исходников которого нет, что теперь? G>В .NET очень легко — берешь dll и достаешь исходники.
Отличный способ
G>В С++ — хз что делать, даже твой способ нельзя применять, ибо гарантий никаких.
.
EP>>>>>>Что значит особый случай? Точно также можно завернуть tcp_stream. G>>>>>Надо очень хорошо знать как код работает внутри, чтобы делать такую асинхронность. EP>>>>Есть любая асинхронная функция которая принимает continuation/.then — мы ей передаём в этот continuation код с yield-ом внутри, что механически превращает остаток нашей функции в продолжение. G>>>Пример давай. EP>>Пример.
// 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.
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
(это при том что я сам практически не работаю ни с каким io). G>>>Без асинхронного IO это все смысла не имеет. Покажи пример с асинхронным IO. EP>>Слушай, ну если ты не нацелен на конструктив, давай прекратим, ок? По второй ссылке Boost.Asio — самое что ни на есть асинхронное I/O, с тем самым IOCP под капотом G>И как это комбинировать? Как запустить два параллельных считывания?
Через boost::asio::spawn
G>>>Ты вообще представляешь как медленно будет работать твой пример с getline на реальном файле? G>>>Опубликуешь результаты забегов? При этом масштабирования такой подход не добавил. Ты не сможешь также запустить 100500 чтений файлов и выйграть хоть что-то. EP>>getline может читать из любого стрима, например из сокета. В одном потоке будут крутится тысячи потоков с getline внутри, который ничего не знает об корутинах. G>И что? Все равно то, что ты показал будет тормозить. Скорее всего аццки тормозить.
Здравствуйте, hi_octane, Вы писали:
J>>Пример Яху всем известен, правда? Пара маргиналов написали систему на маргинальном языке (лиспе) и свалили. Яху помучилась-помучилась и переписала все на мейнстримовом языке.
_>Пример яху как раз шикарен. Пара маргиналов на маргинальном языке внезапно! в ошмётки порвала многочисленных конкурентов на мэйнстримовых языках, за что и были были куплены яху. Тут бы уже задаться вопросом, а с чего бы им это удалось?! Но ты акцентируешь внимание на том что в яху не смогла ни самих маргиналов удержать, ни проект ими поднятый, выдаёшь это за некое преимущество мэйнстримовых языков
Перечитай мое сообщение еще раз, что ли Я даже не знаю, что тут еще сказать.
_>А мне кажется, то что менеджмент яху, в отличии от раннего гугла, не умел строить бизнес силами маргиналов, как раз и есть причина их быстрого слива по всем направлениям
О чем я и говорил в том сообщении, на которое ты отвечаешь
Здравствуйте, Ikemefula, Вы писали:
EP>>Ещё раз. Я озвучил факт, который оппонент не знал/не понимал. I>Ты сам себе придумал, что ктото чего то не понимает.
Например gandjustas начинает петь ту же самую песню про message pump, которую ты пел летом
I>Ну значит UI Loop из моего примера вызовется чудом, например сканированием адресного пространства на предмет наличия ::GetMessage и ::TranslateMessage или, как вариант, короутина догадается WinMain вызвать.
Репертуар "Осень 2013":
EP>>Ну ты говоришь что преобразование синхронного кода в асинхронный это механическая операция. Так и преобразование кода с await/yield — точно такая же механическая операция
G>Во-первых это не так из-за message pump.
EP>>Вот ты тоже не знал, не верил, отрицал. Зато теперь "И что с того ?" — большой прогресс I>Если тебя подводит память, то я напомню — ты утверждал, что асинхронщину не надо всовывать в эвентлуп. И доказал это утверждение кодом в котором всунул асинхронщину в WM_CHAR.
Здравствуйте, Ikemefula, Вы писали:
I>>>Вот такие фокусы и в джаве, и в дотнете, и в питоне. EP>>Откуда именно тут coroutine, покажи полный код на C#. I>Из либы. Зачем тебе код ?