Здравствуйте, alex_public, Вы писали:
_>Смотри, есть реальная асинхронность (как в МК): при попадание байта в сетевую карту мгновенно (ну на самом деле перед этим процессор выполняет ещё кусок кода, но строго фиксированного) выполняется наш код обработки этого байта. Есть классический синхронный код: пользовательский поток блокируется после запуска операции, при приходе соответствующего байта в сетевую карту, ядро ОС ставит флаг, разблокирующий поток и через какое-то время планировщик потоков при возможности запускает код обработки этого байта. А так называемый асинхронный код в Windows работает для одной одновременной операции в точности как описанный выше синхронный код (в качестве ждущего потока сидит не пользовательский, а iocp поток), только плюс ещё куча ненужных сервисных операций (связанных с очередью), плюс ещё возможно надо будет подождать, когда освободится от текущих задач пользовательский поток (т.к. у нас там сопрограмма и поток может быть занят другими сопрограммами).
Результат io операции в асинхронном случае получает iocp поток, зачем ему ждать пользовательский поток? Т.е.
callback (это же можно назвать сопрограммой?) будет выполнен в контексте iocp потока.
Здравствуйте, alex_public, Вы писали:
_>По настоящему, это если бы ядро винды запускала callback в пространстве целевого процесса непосредственно после обработки данных драйвером. Вне каких-либо потоков и их стеков. Приблизительно как работают сигналы в Линухе. Но это слишком сложный и опасный инструмент для прикладного программиста — лучше уж пускай реакция будет хуже (латентность выше), но зато код обработчика будет выполняться в понятном контексте прикладного потока.
Как что-то (т.е. какой-либо код) в пространстве процесса может быть запущено без потока и стека? Или имеется в виду запуск callback'а в самом ядре, а там
разве нет потоков, стеков?
_>А вот в случае одной одновременной задачи у тебя там вполне себе будут заблокированные потоки (и скорее всего их будет даже больше, чем в случае обычного синхронного запроса — я не в курсе какой размер пула iocp потоков в .net по умолчанию, но весьма вероятно что больше 1).
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>2) В дотнете есть такая штука как TPL. Вот это уже та самая асинхронность.
Не согласен. Task Parallel Library это не та самая асинхронность. Это параллельность, многопоточность и т.д.
А асинхронность, это когда одним потоком(одним task'ом) за счет соотв. механизмов можно переделать кучу заданий.
Т.е. один поток + select\epoll и т.п. В дотнет это что-то типа Begin***+End*** + iocp потоки.
Здравствуйте, Kolesiki, Вы писали:
K>Ребят, тема на подумать, "вы не решайте сгоряча"! K>Зачем нам нужна асинхронность? (в контексте GUI программ, взаимодействующих с юзером) K>Весь принцип работы юзера — это некий экшн (клик, нажатие) и исполнение средой соотв. команды. K>MS просто из кожи вылезла, доказывая нам, какое она "бобро" сотворила, наворотив своих async/await. Даже API везде искорёжила в угоду "новому тренду". K>А я вот так смотрю на работу программы и не вижу в этом никакого смысла. K>Заметьте — я ничего не говорю про мультипоточность — она нужна, хотя опять же, далеко не везде. K>Но вот async?... K>Пусть это будет команда Save. Мы нажали, асинхронно вышли из метода, куда-то даже полезли нажимать другие команды, а save всё ещё работает! Хуже того — у неё могут возникнуть проблемы! K>Ну и вот какой смысл "не ждать завершения команды", если всё равно тебе прилетит по лбу? Хуже того — ты понадеялся на УСПЕШНЫЙ сэйв, а документ уже испортил!
В этом плане хорошо придумали в IntelliJ IDEA. Там вообще в своё время отказались от сохранения как синхронной команды которую надо явно вызывать. Ты просто работаешь с файлами, меняешь их, добавляешь, удаляешь, а Идея в фоновом режиме, асинхронно, сохраняет все твои действия в виде истории изменений, как будто это гитовый репозиторий, и предоставляет относительно удобный GUI для браузинга и управления этой историей — возможность вешать метки на файл или даже всю папку, возможность откатиться к какой-то версии, события типа изменений файлов какой-то другой программой отображаются в этой истории как событие "External change", можно сравнить две версии. Сейчас, насколько знаю, и другие IDE начали делать нечто подобное с той или иной степенью убогости — от VS до Delphi, но ЕМНИП идеевцы были первыми и сделали это как всегда круто, качественно и удобно — поэтому если порча файла по какой-то причине и была, то в 90% случаев по локальной истории можно восстановить наименее испорченную версию файла — и это не раз меня и коллег спасало, бывали даже случаи, когда код безвозвратно терялся в удаленном репозитории, но его доставали из этой локальной истории.
K>По-моему, даже если команда выполняется "долго" (1+ секунд), нет вообще никакого смысла скрывать её за "отзывчивым интерфейсом", потому что если мы командуем, мы ждём РЕЗУЛЬТАТА команды! K>Более того — если подразумевается ещё более долгая работа (5+ секунд), такие действия должны заворачиваться в "диалог прогресса + немедленной отмены". Зачем тут async? K>У меня со времён этой "распеаренной асинхронщины" была куча ГУЁВ, я даже пытался что-то наасинхронить (типа "долгая работа с Тырнетом"), но вот факт тот, что ВООБЩЕ НИГДЕ эта асинхронность не лезла!
Вот в той же Идее многое сделано асинхронно, и у них оно всё "залезло" — валидация кода, подтягивание мавеновских зависимостей, компляция. Представить, что всё это вдруг станет синхронным — это просто застопорит работу, хотя раньше видимо прогеры кодили синхронно и особо не напрягались (хотя вот по себе помню, когда кодил в древние времена на дельфях или турбо паскале, то компиляция была быстрая и особо не напрягала, но когда на Си++, с его длинными компиляциями и линковками, то уже эта синхронность заметно подбешивала, нарушая "ощущение потока").
Здравствуйте, Sharov, Вы писали:
S>Не согласен. Task Parallel Library это не та самая асинхронность.
Это та самая. Асинхронность в виде фьючерсов и fine grained распараллеливания. Зачем ты выделил слово Task я вообще не понял.
S> Это параллельность, многопоточность и т.д.
Нет. Многопоточность в TPL штука опциональная. Те самые однопоточные контексты в WinForms, WPF и ASP.NET старом — это все равно TPL и его таски. Вся специфика находится внутри TaskScheduler и SynchronizationContext, причем последний появился еще до TPL.
S>А асинхронность, это когда одним потоком(одним task'ом) за счет соотв. механизмов можно переделать кучу заданий.
Асинхронность это отсутвие синхронного выполнения. В случае TPL синхронный поток выполнения заменяется на набор кусочков (тех самых тасков в названии), связанных между собой колбеками и образующих тем самым структуру данных вместо императивного кода. Это основа, то вокруг чего все остальное построено.
А уж полученную асинхронную структуру можно выполнить как на одном потоке, так и на нескольких, с использованием IOCP и без него.
Здравствуйте, Sharov, Вы писали:
_>>А вот в случае одной одновременной задачи у тебя там вполне себе будут заблокированные потоки (и скорее всего их будет даже больше, чем в случае обычного синхронного запроса — я не в курсе какой размер пула iocp потоков в .net по умолчанию, но весьма вероятно что больше 1).
S>По числу ядер, домноженное, наверное, на 2 (ht).
Здравствуйте, alex_public, Вы писали:
_>использовать её вообще для всего (даже для банального чтения одного конфигурационного файла). Хотя на самом деле, для большинства случаев классический синхронный ввод-вывод и проще и эффективнее.
У асинхронных версий, обычно, есть такая штука как CancellationToken. Очень, знаешь ли, улучшает отзывчивость. МС, правда, не доработал местами. Операция удаления до сих пор отменяться не умеет, что при работе со всякими сетевыми шарами довольно весело.
Здравствуйте, ononim, Вы писали:
O>SignalAndWaitForSingleObject по сути должна быть оптимизирована под такой сценарий. Она там внутри сигналит ивент и не отходя от кассы — не отпуская лок шедулера — начинает ждать другой ивент. Поток который ждет ивент ставиться в очередь на исполнение в момент сигнала ивента, но ставиться на свободный проц, который не текущий, хотя точно известно, что текущий вот-вот освободиться.
Логично. Возможно, этого не стали делать из-за того, что такой сценарий не считается типичным. По идее, если нескольким потокам важно переключаться друг на друга как можно быстрее, то они должны работать с общими данными. А в этом случае им логично привязываться к одному процессору/ядру. Для получения максимальной производительности нужен еще и поток-диспетчер, который будет перепривязывать группу к другому ядру, если прежнее вдруг станет работать медленнее в течение заметного времени.
Кстати, не пробовали перед вызовом функции дергать SetThreadIdealProcessor?
S>>Не согласен. Task Parallel Library это не та самая асинхронность. НС>Это та самая. Асинхронность в виде фьючерсов и fine grained распараллеливания. Зачем ты выделил слово Task я вообще не понял.
Потому что для асинхронности может быть достаточно одной таски(=поток). Библиотека для работы и создания таксков тут может быть излишняя.
S>>А асинхронность, это когда одним потоком(одним task'ом) за счет соотв. механизмов можно переделать кучу заданий. НС>Асинхронность это отсутвие синхронного выполнения. В случае TPL синхронный поток выполнения заменяется на набор кусочков (тех самых тасков в названии), связанных между собой колбеками и образующих тем самым структуру данных вместо императивного кода. Это основа, то вокруг чего все остальное построено. НС>А уж полученную асинхронную структуру можно выполнить как на одном потоке, так и на нескольких, с использованием IOCP и без него.
Очень классно сформулировано . Единственное что не нравится, это слово callback, уж больно оно перегружено. И речь идет о структурах данных,которые могут являться единицами планировки. Т.е. слово future или сontinuation подошло бы больше. Т.е. я бы сказал, что таски связаны продолжениями, а не колбеками. Колбек -- это все-таки механизм, указатель на ф-ию.
Здравствуйте, Sharov, Вы писали:
S>>>Не согласен. Task Parallel Library это не та самая асинхронность. НС>>Это та самая. Асинхронность в виде фьючерсов и fine grained распараллеливания. Зачем ты выделил слово Task я вообще не понял. S>Потому что для асинхронности может быть достаточно одной таски(=поток).
Ничего не понял. Что значит достаточно одной таски и почему это важно? И нет, таска != поток.
S> Библиотека для работы и создания таксков тут может быть излишняя.
Для чего излишняя?
S>Очень классно сформулировано . Единственное что не нравится, это слово callback, уж больно оно перегружено.
В данном контексте оно имеет вполне конкретное значение.
S>Т.е. слово future или сontinuation подошло бы больше.
Future или promise. Но МС любит альтернативную терминологию вводить.
А сontinuation это ортогональное понятие, это не про таски, а про async/await.
S>Т.е. я бы сказал, что таски связаны продолжениями, а не колбеками.
Да, ты прав, можно обойтись без колбеков, например при помощи ждущего потока и эвента.
S> Колбек -- это все-таки механизм, указатель на ф-ию.
Нет. Колбек это принцип. А механизм в дотнете называется делегат.
Здравствуйте, Ночной Смотрящий, Вы писали:
_>>А откуда вообще колбеки возьмутся то? У нас есть некая длительная задача, которую нужно выполнить без заморозки главного потока. НС>Это если тебе в этой задаче не нужно что то периодически от пользователя или сети.
Так сеть (или скажем диск) — это обычно и есть та самая длительная задача. )
_>> Ну так просто запускаем для этого фоновый поток, делаем в нём все нужные нам задачи (через синхронное АПИ ввода-вывода) со сложной логикой и потом просто уведомляем сообщением главный поток (чтобы он например разблокировал соответствующую кнопку в GUI и т.п.) о завершение работы. НС>А если в процессе нужно спросить у пользователя что то?
Тогда этот фоновый поток будет у меня не таким тупым, а станет например актором. С которым gui-поток (тоже есть естественно актор) будет общаться с помощью сообщений. Ну или вместо акторов можно CSP взять — это уже зависит от остальных частей приложения. )
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Почитал тут топик. Как, однако, все запущено, не только у ТС.
Ещё один смешной читатель, пришедший "поучать", вместо "читать". Тебе не приходило в голову, что то, что ты тут пишешь:
НС>1) async/await само по себе — вообще не про асинхронность
и было ПРИЧИНОЙ ТОПИКА?!
Т.е. я, подозревая почти полную бесполезность async/await, запиливаю топик. Набигают студенты и "те, кто знает больше меня", и начинают мне же объяснять, что такое async/await! Чудны крестьянские дети...
Ещё раз прочитай топик, я бы это каждому "поучале" в треде сказал. Русским же языком написал — я знаю ЧТО такое трэды и почему это не одно и то же, что и async/await!
Мой главный вопрос: зачем именно async/await так нужны в C#, если они 1) вообще не про параллельность 2) уже существуют трэды, решающие ВСЕ задачи "параллельного исполнения".
Здравствуйте, Sharov, Вы писали:
НС>>2) В дотнете есть такая штука как TPL. Вот это уже та самая асинхронность.
S>Не согласен. Task Parallel Library это не та самая асинхронность. Это параллельность, многопоточность и т.д. S>А асинхронность, это когда одним потоком(одним task'ом) за счет соотв. механизмов можно переделать кучу заданий.
А я не согласен с твоим узким определением, причём неверным в корне.
Что такое вообще слово "асинхронно"? Это значит, что есть минимум 2 неких процесса, работающих независимо друг от друга (т.е. им не надо синхронизировать друг с другом свою работу). Так что любой трэд, TPL или нечто "сбоку" от главной программы — это и есть "асинхронное исполнение".
Итак, пройдёмся крапивой по набежавшим комментаторам, так отчаянно впаривающих мне про async, наивно думая, что это некое "параллельное исполнение". ДАЖЕ НЕСМОТРЯ НА ПРЕДУПРЕЖДЕНИЕ В АПДЕЙТЕ!
K>UPD K>Как и ожидал, несмотря на тонны материалов по thread и async, некоторые до сих пор думают, что это одно и то же.
async, именованный бестолковой мелкомягкой макакой, таки спровоцировал в нубах "понимание", что это "нечто асинхронное". Объяснять не буду, просто скажу: state machine.
Далее:
K>Зачем нам нужна асинхронность? (в контексте GUI программ, взаимодействующих с юзером)
И опять "чукчи-писатели" начисто проигнорировали слово GUI, полезли в какие-то серверные дебри, веб-сервера, Windows 3.1.... Ребят, вы можете ПЕРЕД комментированием ПОДЫШАТЬ 10 секунд, перечитать топик, вникнуть в проблему и только потом строчить? Ей богу, еле дочитал ваши минусяторские помои! (вообще не по делу)
Попробуем опуститься на уровень примеров — может так будет проще мыслить.
Для примера возьмём всё ту же операцию Save.
Юзер нажимает кнопку, пошёл обработчик этой кнопки. В большинстве случаев люди работают с весьма скромными файлами, запись которых длится едва ли больше секунды, даже на "блинах". Что юзер хочет своей командой? Гарантированное сохранение своего документа. Практически ситуация "макака-банан": жмём клавишу — получаем результат в виде 100% сохранённого файла и соотв. уведомления. (а иначе, зачем вообще жать save, если ты не следишь за сохранностью??) А так как юзер — существо одномозговое, а уведомление приходит по единственному каналу "зрение", то очевидно, что он НИЧЕМ не может/не должен быть занят, чтобы в нужном месте экрана заметить результат операции.
Получается, что никакие async'и и даже трэды ну никак не помогают в цепочке "кнопка-действие-результат"! Что отжата кнопка Save, что нажата, что не перерисована, ЮЗЕРУ ПОФИГ — он ждёт результата. Императивное мышление, пошаговые действия: сделал одно, завершил, переключился на второе. (собственно, почему ФП и слилось, что было ортогонально человеческой императивной природе) И снова возникает вопрос: что ПОЛЕЗНОГО даст этот жёваный async/await в цепочке юзерских действий? Ну, кроме того, что кнопка "красиво отожмётся" ранее, чем закончитатся мгновения сэйва.
И так не только с сохранением — ВСЁ, что вы "командуете" программе через тулбар, имеет свою чёткую процедуру исполнения и практически бессмысленно давать юзеру "интерактив" ранее, чем полное завершение команды. Это касается "быстрых" команд. Вот на этом моменте выдохните, осознайте что я хочу сказать и только потом приступайте к коментам.
Ну а "длинные" команды типа аплоадинга файлов или компиляции, как я и говорил, прекрасно решаются трэдами с диалогом отмены. Тут очевидно, что нет смысла "держать" юзера — пусть занимается своим делом и в конце рапортуем о результате. Хотя вот как раз канпеляние ТОЖЕ БЕССМЫСЛЕННО делать async'овым, потому что юзеру нужен результат. Никакие "действия" во время компиляции продуктивности не повысят. Скомпилял, запустил — ВОТ что хочет юзер.
Итак, если вы НАКОНЕЦ где-то прочитали, как внутри работает async/await и какой в них профит программе (по версии MS), снова зададим тот же вопрос: зачем нам async?
PS
Извините, в топике я таки был некорректен, каюсь — не "асинхронность", а "async". Но сам пост прекрасно поясняет, что именно "ненужно" в C#.
Здравствуйте, alex_public, Вы писали:
_>Тогда этот фоновый поток будет у меня не таким тупым, а станет например актором. С которым gui-поток (тоже есть естественно актор) будет общаться с помощью сообщений. Ну или вместо акторов можно CSP взять — это уже зависит от остальных частей приложения. )
А можно взять модель фьючерсов, которая тоже имеет право на жизнь.
Здравствуйте, Kolesiki, Вы писали:
K>Мой главный вопрос: зачем именно async/await так нужны в C#, если они 1) вообще не про параллельность 2) уже существуют трэды, решающие ВСЕ задачи "параллельного исполнения".
K>Итак?...
Здравствуйте, Sharov, Вы писали:
_>>Смотри, есть реальная асинхронность (как в МК): при попадание байта в сетевую карту мгновенно (ну на самом деле перед этим процессор выполняет ещё кусок кода, но строго фиксированного) выполняется наш код обработки этого байта. Есть классический синхронный код: пользовательский поток блокируется после запуска операции, при приходе соответствующего байта в сетевую карту, ядро ОС ставит флаг, разблокирующий поток и через какое-то время планировщик потоков при возможности запускает код обработки этого байта. А так называемый асинхронный код в Windows работает для одной одновременной операции в точности как описанный выше синхронный код (в качестве ждущего потока сидит не пользовательский, а iocp поток), только плюс ещё куча ненужных сервисных операций (связанных с очередью), плюс ещё возможно надо будет подождать, когда освободится от текущих задач пользовательский поток (т.к. у нас там сопрограмма и поток может быть занят другими сопрограммами). S>Результат io операции в асинхронном случае получает iocp поток, зачем ему ждать пользовательский поток? Т.е. S>callback (это же можно назвать сопрограммой?) будет выполнен в контексте iocp потока.
Я тут имел в виду, что если ты напишешь что-то вроде:
data=await DownloadFile();
Parse(data);
в gui потоке, то функция parse опять же будет вызвана в gui потоке, который на момент отработки соответствующего Iocp потока вполне может быть чем-то занят.
Здравствуйте, Sharov, Вы писали:
_>>По настоящему, это если бы ядро винды запускала callback в пространстве целевого процесса непосредственно после обработки данных драйвером. Вне каких-либо потоков и их стеков. Приблизительно как работают сигналы в Линухе. Но это слишком сложный и опасный инструмент для прикладного программиста — лучше уж пускай реакция будет хуже (латентность выше), но зато код обработчика будет выполняться в понятном контексте прикладного потока. S> S>Как что-то (т.е. какой-либо код) в пространстве процесса может быть запущено без потока и стека?
S>Или имеется в виду запуск callback'а в самом ядре, а там разве нет потоков, стеков?
Да, в ядре нет потоков. Но я подразумевал естественно не запуск колбеков в ядре, потому как ядро исполняется с привилегиями нулевого кольца, которые нельзя давать коду пользовательских приложений. Я имел ввиду что ядро могло бы напрямую инициировать запуск пользовательского кода, но естественно только внутри пользовательского процесса, в 3-ем кольце защиты.
_>>А вот в случае одной одновременной задачи у тебя там вполне себе будут заблокированные потоки (и скорее всего их будет даже больше, чем в случае обычного синхронного запроса — я не в курсе какой размер пула iocp потоков в .net по умолчанию, но весьма вероятно что больше 1). S>По числу ядер, домноженное, наверное, на 2 (ht).
Ну т.е. при таком подходе у тебя априори в разы больше висящих в блокировке потоков, чем при честном сихнронном вводе-выводе в отдельном потоке. ))) И да, на самом деле в этих висящих потоках конечно же ничего страшного нет. Просто не надо мифологизировать, что их нет, как вот в той бредовой статье.