Как стать автором
Обновить

Комментарии 62

А откуда именно потом будет вызвано continuation? Из главного event loop-а?
ну будет наверно какой-нить Dispatcher как в WPF, который будет в event loop вызываться.
Да я просто думаю, делать логику сервачка по-старинке через yield или таки попробовать использовать async. С yield не будет лишних потоков, а вот как работает с сокетами async, пока не ясно.
Насколько я понимаю, вся эта эпопея с await затеяна именно для облегчения интеграции многопоточности с UI. В случае с программой без него, не будет никакого профита от продолжений, которые выполнятся в случайном потоке из пула, только накладные расходы.
Из System.Threading.SynchronizationContext.Current
Отлично, а его кто пинает? Ну не может быть такого, чтобы посреди выполнения кода (который вполне может быть внутри какой-нибудь блокировки) его прерывали и переключали контекст на continuation.
Если я все правильно помню, для не UI кода по умолчанию это все реализовано через ThreadPool и егошний диспетчер, т.е. никакой код не прерывается, просто берется свободный поток из пула или создается новый. В случае с UI — используется Dispatcher UI фреймворка (WinForms, WPF, SL), чтобы обеспечить выполнения продолжения в контексте UI потока.
Так оно в итоге только для UI-потоков гарантирует, что continuation будет вызван в том же потоке, в котором вызвали метод через await?
Не совсем. По умолчанию для не UI потоков не задан какой-то специфичный SynchronizationContext, поэтому выполнение идет через TaskScheduler.Current, который просто раскидывает задачи по потокам из пула. Но у вас всегда есть возможность задать свой SynchronizationContext, в котором определить требуемое поведение.
В С++11 появилась схожая штука: ::std::async.
Передав в нее функцию, на выходе получаем ::std::future (continuation вообщем-то).
Пока результат нам не нужен — делаем посторонние задачи. Как нужен — вызываем метод get() у ::std::future, который или сразу вернет результат (если он уже посчитан) или заблокируется пока результата не будет.

К чему я это — к тому что асинхронность добавляется в разные языки, а значит набирает популярность у неискушенных программистов.
Аналог того, что вы описали, было в C# задолго до async/await.
А в чем тут отличие? Я с Си-шарпом только в универе был знаком.
Ну была штука под называнием IAsyncResult, которую возвращали асинхронные методы. Очень давно была.
Любые методы или какие-то специально написанные? Если любые — так это понятно, это особенность конкретной библиотеки. А ::std::async это особенность языка — он принимает любую синхронную функцию, кладет ее в очередь, занимается пулом потоков — это все теперь проблемы языка и реализации стандартной библиотеки.
Тьфу, наоборот
>> Если любые — так это понятно
Следует понимать как
>> Если специально написанные — так это понятно.

Да, я посмотрел IAsyncResult ну это просто стандартный интерфейс под хэндл, а не механизм же.
Можно брать _любую_ функцию и вызывать ее через делегат
Ок. Посмотрю еще. А чем отличается от нововведения, описанного в статье?
Там просто запуск кода в фоне с возможностью потом его синхронно подождать. Описанное в статье возвращает выполнение в вызывающий код сразу, а уже потом из event-loop-а будет вызван обработчик результата, причём сам код пишется так, как будто он синхронный.
Ну вот вы писали "… который или сразу вернет результат (если он уже посчитан) или заблокируется пока результата не будет." Работа с IAsyncResult примерно такая же (хотя есть дополнительные плюшки). Плюсы async/await как в упрощенном синтаксисе (код выглядит как синхронный), так и в отсутствии необходимости самому опрашивать возвращенный «специальный» объект на наличие результата. Ничего блокироваться не будет.
Это часть того, что называется в дотнете APM — asynchronous programming model. Классы, которые поддерживают асинхронное выполнение, должны следовать рекомендациям по их оформлению соответствующим образом. К примеру, если обычный метод назывался DoSomething, то его асинхронная версия должна быть парой методов BeginDoSomething/EndDoSomething. Begin-метод должен возвращать IAsyncResult, а End-метод принимать его в качестве аргумента.
А IAsyncResult вы можете реализовать как вы хотите (если вы делаете асинхронный API). Это не обязательно просто хранилище для хендла, в общем случае это объект, представляющий собой контекст выполняемой асинхронной операции.
>В С++11 появилась схожая штука: ::std::async.
ничего общего с асинками в C# 5
автор шарповых асинков уже работает над тем же самым для будущего C++
Да, мне уже объяснили.

Ох, «будущий С++». Саттер сказал, что еще года 3 книг по С++11-то не появится, так как мало опыта. Так что «будущий С++» будет лет через 10. Если будет, конечно…
>Саттер сказал, что еще года 3 книг по С++11-то не появится, так как мало опыта.
появятся, на GoingNative у кого-то на слайде были примерные даты по выходу новых изданий известных книг по Си++.

>Так что «будущий С++» будет лет через 10
Последнее время к Си++ снова возрастает внимание, а вместе с ним и финансовые вливания. Так что думаю что будущий Си++ не придётся ждать так долго.

А если хочется аналога шарповых асинков прямо сейчас, то можно с помощью небольшой магии с макросами сделать примерно тоже самое, все детали по асинкам разжованы в блогах майкрософтовцев.
Вы ведь смотрели GoingNative?
Там фраза и про стандарт была, что еще даже загадывать рано и сейчас основная проблема — библиотеки. Нужно хотя бы лет за 5 набрать объем сопоставимый с с# и java.

Про книги я оттуда же и взял: и серьезные книги (типа Exceptional C++ или Effective C++) это как раз через 3 года минимум.
Если C++0x планировали «ну точно» доделать до 2009-го, а потратили восемь лет, при этом выкинув часть планируемых фич, то шансы, что уложатся в шесть лет, я бы сказал, невелики. :)
Выглядит действительно вкусно. Жаль, нескоро это появится у большинства пользователей. У многих не то что 4.5, даже 4.0 то не стоит )
Windows 8 думаю с 4.5 выпустят, или только 4.0 там будет?
4.5 я надеюсь)
Однако, учитывая крупные изменения в Win8, далеко не факт, что народ туда быстро перелезет.
У XP то все еще довольно весомая доля рынка…
Ну накатят Service Pack обязательный на XP и семерку, и там 4.5 присунут.
Хотя вроде дальше SP3 на XP сказали что не будут делать.
Не накатят) На XP точно нет.
выпустят вместе с 4.5
пруф
А в чём проблема таскать фреймворк с собой?
НЛО прилетело и опубликовало эту надпись здесь
Плюс ко всему можно даже не таскать с собой, а в инсталлере проверять его наличие, и грузить в процессе установки, при необходимости.
Так и делаю. Проблема в том, что у некоторых юзеров возникают проблемы с установленным ранее .NET. Не работает программа, пока не переустановишь его с нуля. Правда, к наличию изначально у юзера .NET это отношения не имеет, согласен.
А можно поподробнее?
Возникают совершенно безумные эксцепшны при инициализации главного окна программы.
Что то вроде:
Исключение 0: Инициализатор типа «System.Windows.Media.FontFamily» выдал исключение.
0: — Void System.Windows.Media.Typeface..ctor(System.Windows.Media.FontFamily, System.Windows.FontStyle, System.Windows.FontWeight, System.Windows.FontStretch)
0: — System.Windows.Media.Typeface MS.Internal.Text.DynamicPropertyReader.GetTypeface(System.Windows.DependencyObject)
0: — Void MS.Internal.Text.TextProperties.InitCommon(System.Windows.DependencyObject)
0: — Void MS.Internal.Text.TextProperties..ctor(System.Windows.FrameworkElement, Boolean)

с внутренним эксцепшном

Исключение 1: Исключение из HRESULT: 0xD000009C
0: — Void System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32, IntPtr)
0: — Void System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32, IntPtr)
0: — Void MS.Internal.Text.TextInterface.Native.Util.ConvertHresultToException(Int32)
0: — MS.Internal.Text.TextInterface.FontCollection MS.Internal.Text.TextInterface.Factory.GetSystemFontCollection(Boolean)
0: — MS.Internal.Text.TextInterface.FontCollection MS.Internal.FontCache.DWriteFactory.get_SystemFontCollection()
0: — Void System.Windows.Media.FontFamily..cctor()

или какой то компонент не находится. или просто пишет что не удалось проинициализировать программу корректно.

Использую .NET 4.0 и WPF
Эксепшены всегда связаны со шрифтами?
Нее… Иногда не может найти System.Web, это я так понимаю если Compact Framework стоит. Иногда еще чего не может найти. Иногда в XAML ему что-то не нравится. В общем, странные эксцепшны.
Первый раз слышу вообще о таких багах, может на целевых компьютерах файлы .net повреждены?
Ну так я и написал) Скорее всего у них он поврежден. Поэтому переустановка помогает в 99% случаев. В оставшемся 1% видимо вся система через жопу установлена или загажена до такой степени.
Возможно, у них просто стоит ClientProfile? Или как вариант, не накачены патчи, которые вам нужны?
ClientProfile объясняет только некоторые из эксцепшнов)
Патчей никаких мне не надо)
BackgoundWorker можно закапывать?
BackgroundWorker для тасков с апдейтом прогресса нужен будет.
Ух ты, монада!
Как только фоновый поток завершит работу и вернет результат — будет выполнено «продолжение» в основном потоке — могу сильно ошибаться, но вроде как это не всегда так. Т.е. «продолжение» может быть вызвано в совсем другом потоке нежели начало метода. Все зависит от того, как настроен текущий Dispatcher. В случае с WPF/Winforms приложений Dispatcher всегда вызывает код таски и ее продолжения в UI потоке. В общем случае это не так.

Кстати, это может привести к очень трудноуловимым багам. Представьте следующий код:
lock(syncRoot)
{
await Download();
}

Да, он не очень логичен и даже не скомпилируется (внутри lock и catch await делать нельзя).
Беда в том, что многие текущие синхропримитивы привязаны к тому, что код внутри них выполняется в одном потоке, а с тасками это не всегда так.
Совершенно верно, все зависит от текущего диспатчера. Вообще не вижу особого смысла применять эту технику для не UI потока, если только ради более красивой обработки исключений )
Для не UI потока это точно так же полезно, поскольку код становится проще и понятней. Попробуйте переписать любым другим образом код, который будет содержать 3-4 вызова await. Там такая каша получится, будь здоров.

Еще один плюс await-ов в том, что они делают один лексический скоуп, что позволяет пользоваться такими вещами, как using, try/finally и т.д.

Т.е. это не просто более красивый код обработки исключений, эти штуки дают более читабельный код, который можно спокойно читать без боязни заработать непоправимые заболевания от вывиха извилин.
Мне несколько раз приходилось писать туже самую state машину, что генерируется await'ами, но на ManualResetEvent'ах — выглядело ужасно. С await'ами же все это укладывается в несколько строчек.
Встречайте, FCC :D
А unwind-protect не асилили. Слабаки
Красиво и понятно. Спасибо за объяснение. Жду с нетерпением!
Когда сложное объясняется просто :) Спасибо!
А await коллекции возможен? Например, запустить обсчет AI четырех персонажей (соответственно в четырех потоках), а когда все расчеты закончатся — что-то продолжить делать.
Это через Parallel Extensions делается вообще говоря.
В общем виде это будет выглядеть как-то так:

    List<Person> persons;
    ...
    await TaskEx.WhenAll(from p in persons select p.ProcessAsync());
    ...
    продолжение


Вот здесь в видео примерах есть применение WhenAll
— забегая вперед стоит сказать, что await умеет работать только с функциями возвращающими Task и Task.

Ты ошибаешься. await будет работать с любым типом, имеющим метод(или экстеншн метод) GetAwaiter()
Ну короче тоже самое, как и foreach, которому совсем не нужен IEnumerable. Достаточно того, чтоб тип имел метод GetEnumerator. Или как query syntax в линке. Реализуй для int'а экстеншн методы Select/Where/SelectMany и пиши спокойно:
var _ = from x in 10
from y in 20
where y > 15
select x + y;
с таким косяком «особенностью» в Exception Handling — этот концепт становится алогичным и неприменимым.
Именно поэтому методы имеющие в теле await отмечаются как async. Нужно просто правильно использовать технологию… асинхронность как ни круто будет накладывать ограничения. Новый синтаксис сильно сокращает количество инфраструктурного кода + облегчает обработку исключений, но нельзя же ждать чтобы код вел себя совсем уж как синхронный
Task<string> task = new WebClient().DownloadStringTaskAsync("http://microsoft.com/");
task.Wait(); // Здесь мы ждем завершения задачи, что блокирует поток
TextBox.Text = task.Result;

Конечно, посту уже 100 лет. Но вот что-то мне кажется, что Вы не проверяли это.
Такая штука работать не будет)
Почему?
Все отлично работает.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории