Pull to refresh

Comments 48

>>Например, если раньше можно было считать данные из файла одной строчкой вида:
>>string[] lines = File.ReadAllLines(«filename.txt»);
>>Теперь это будет что-то такое:
>>IList lines = await ReadFileAsync(«filename.txt»);
Ужас!!! на целое слово больше! (и, сцуко, не заблочит UI пока будет читать гиговые файлы — вот жеж!)

async\await — одна из лучших фич в шарпе имхо. Просто надо уметь их готовить (знать про sync context и во что разворачивается)
А почему не каждую функцию можно сделать асинхронной?
Оно сопротивляется… Я, к сожалению, до недавнего времени с async...await не дел не имел — самому еще много изучить надо
async void — для асинхронных методов которые запустил и забыл про них, так помечаются методы, в которых используются асинхронные вызовы. Так можно пометить, например, обработчик события.

async Task/Task — для асинхронных методов, завершения выполнения которых необходимо дожидаться, то есть использовать конструкцию await ...;
В второй части ответа Хабр проглотил угловые скобки.
В принципе можно любой функции приписать тот самый async, но если в этой функции не будет вызываться какой-то асинхронный метод, то компилятор ругнётся, что мол «async method lacks 'await' operators».
Но это всего лишь warning.
Я вот узнал, что конструктор нельзя делать асинхронным. Что в принципе логично, было-бы немного странно, если бы конструктор типа T возвращал Task.
Ну по сути Вы можете сделать конструктор как async void, но от проблем, тянущихся за такими объявлениями Вы уже не застрахованы :)
Но всё подробнее об этом расписано тут: stackoverflow.com/questions/8145479/can-constructors-be-async
Я могу сказать даже больше. Код из последнего примера должен «виснуть» всегда, когда он запускается из GUI потока (возможно, за исключением режима отладки). И что Вы имели в виду под словами «Естественно, что не каждую функцию можно так пометить»?
Тут две проблемы, они связаны:
— не каждую функцию можно пометить как async. Навскидку — static конструктор, который должен отработать при старте программы и прочитать что-нибудь из файла с данными для работы.
— отсюда проблема №2: что делать, если мне надо прочитать данные из файла, но делать я это могу только из метода, который нельзя сделать асинхронным?

P.S.: кстати, добавление try...catch в последний пример вроде бы решает проблему зависаний. По-крайней мере у меня не получилоcь :)
Я просто в синхронном потоке вызываю асинхронную функцию без присвоения, тогда await не нужен, а обработка функции пускается на самотек. Внутри же функции устанавливаю глобальный флаг доступности (заодно можно пользователю включить колесико загрузки), делаю все полезное, а потом флаг доступности снимаю. А во всех связанных функциях перед работой проверяю значении этого флага. Заодно можно обезопасить себя от ситуаций, когда пользователь нажимает кнопку типа «Обновить» по 5 раз.
В топике есть ответ на вашу проблему #2:
var res=MyAsyncFunction();
    res.Wait();
    if(res.Result==...) ...;
данный код иногда вешает все приложение. Причем непредсказуемо и блоком try...catch ошибки не отлавливаются, Visual Studio их тоже в упор не видит. Так что пока я не уверен в его правильности
И правильно вешает, вы же асинхронную операцию пытаетесь выполнить синхронно.
Насколько я понимаю, данный код «замораживает» текущий поток на время выполнения асинхронной функции. Если только в самой функции нет бесконечного цикла, то по идее именно «зависания» не должно происходить. В том числе и если в асинхронной функции выбросилось исключение. Или я не прав?
Не вижу причин, почему try/catch в этом коде спасает от зависания.

Да, замораживает. Если это главный поток, то заморозка его даже на секунду даст видимый лаг в интерфейсе.
Исключения не передаются между потоками, поэтому try/catch в основном потоке не поймает исключение из второго
Если второй поток упадет, то он не успеет сообщить первому о завершении — следовательно первый будет ждать бесконечно долго.
Тогда вопрос по реальной ситуации:
— есть класс, который загружает данные из переданной ему в конструктора ссылки на файл.
— файл 100% существует и доступен для чтения
— размер файла меньше килобайта — следовательно должен прочитаться практически мгновенно

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

Отсюда вопрос — как этот кусок кода может зависнуть? Он не использует внешние переменные в которые может идти чтение/запись в других потоках, он полностью независим от остальной программы. Чему там виснуть? А оно зависает… Почему?
Почему оно зависает в вашем конкретном случае, мой хрустальный шар не показывает. Там может быть что угодно, от стареющего диска до ошибок ОС.
Мне кажется что запускать в конструкторе ресурсоемкие операции неверно
Мне надо было десяток строчек из двух файликов прочитать. А вообще, для этой задачи похоже надо копать в сторону работы с настройками
Чтобы не спорить — набросал быстренько маленький тест при котором в асинхронном таске происходит необработанное исключение. Ничего не зависает — исключение корректно передается в основной поток (правда обёрнутое в AggregateException).
Ловится try/catch'ем в основном потоке или глобальным обработчиком исключений в приложении.

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            try
            {
                GetValueAsync().Wait();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public Task GetValueAsync()
        {
            return Task.Run(() =>
            {
                Thread.Sleep(1000);
                var i = 0;
                return 10/i;
            });
        }


Ничего удивительного, что они не отлавливаются и вешают приложение. Исключения ловятся в том потоке, в котором они произошли. В главном потоке вы ждете другой, если тот упадет по неотловленному исключению, ваше приложение останется ждать его бесконечно.
Если по каким-то причинам вы не можете использовать синтаксический сахар в виде async/await — объявляйте три функции в явном виде.
Есть еще варианты: через AsAsyncOperation и подписаться на event и через awaiter в цикле.
Самый лучший вариант — это MyAsyncFunction().ConfigureAwait(false)
UFO just landed and posted this here
Вопрос из самой глубины колхоза: сколько надо будет собрать граблей, создателю какого нибудь дефрагментатора с Win/Metro UI? :-)
Ну например само Metro-приложение — только обертка, а все реальные действия выполняет собранное по старинке обычное приложение, вызываемое отдельным потоком из обертки
… причем общаться друг с другом они будут используя собственный протокол вида myprotocol://Короче, прилично это не описать :)
По идее, через обычный ремоутинг поверх пайпа. Три строчки кода и потом всё прозрачно. Или я не прав?
А нафига козе боян в планшетном интерфейсе дефрагментатор?
Ну, лично мне, было бы интересно наблюдать за процессом, обновляющемся в реальном времени на красивой плитке. Проблема в том, что по факту, чтобы это произошло надо следующее:
— в системе должен быть сервис, который посылает данные на сервер Microsoft
— с сервера Microsoft данные уходят в программу, которая обрабатывает эти данные и выводит их на плитке

Короче, это как рвать гланды не через рот
Я полагаю у красивого окошка больше возможностей отображать красиво процесс в реальном времени.
Вам уже сказали, что если использовать собственный протокол, то сервер МС вам не нужен.
Зачем все это городить тем более непонятно, что на ARM это работать не будет.
Насколько я понимаю — на арм'ах в любом случае будет свой софт, и далеко не факт что он будет совместим с PC-версией
насколько я понимаю, WinRT был создан именно для того, что бы софт не зависел от процессора. Посмотрите в магазин приложений, я не нашел таких (кроме тех что desktop) которые не поддерживали бы ARM.
И, как всегда, невозможность указать на момент инсталляции местоположение домашней директории пользователя, убивает все прелести от ее использования…
Логика весьма интересная. Я хочу для планшета написать программу управления атомным реактором, а мне не дают.
Насколько я понимаю, логика появления WinRT весьма проста. Вы пишите приложения, которые не могут сломать операционную систему и/или окружающие приложения. Причяем добиться этого необходимо любыми способами. Почеиму? Да потому, что переустановить Windows 8 на планшет — рядовой пользователь не сможет.
Хотите приложение работающее с файлами, WinAPI и т.д., пишите обычное приложение, оно будет запускаться на полнофункциональных ПК. Ну а если оно уронит ОС или еще чего, то переустановка вам в помощь.
Почему же не дают? Дают. Пишите своё приложение, но рассчитывайте, что у вас планшет, на котором всегда может сесть батарея, и вообще, его в метро запустили, там сеть лишь по 3G (в лучшем случае), да и то, постоянно отрубается в тоннелях. Кроме того, приложение будут постоянно закрывать (на переходах между станциями пользователь уберёт планшет в сумку, чтобы не уронить). От сюда все ограничения.
Блин, ну когда же я научусь писать тег сарказм… Первая строка в предыдущем коментарии, это сарказм в сторону статьи, в котрой автору обидно, что из приложения для планшета не дают делать то же, что и из десктопного приложения.
res.Wait();

Этим кодом вы убиваете сам смысл async. Зависает он в том случае, если фоновый поток изнутри вызова MyAsyncFunction планирует обратный вызов в GUI-потоке через диспетчер и ждет его. Классический сценарий дедлока. Поэтому никогда нельзя дожидаться выполнения асинхронного кода в GUI-потоке, что в WinRT, что в WPF, что в Silverlight. Правильный подход — в обработчике нажатия кнопки — заблокировали GUI от повторного вызова (задисейблили кнопку), начали выполнение асинхронного кода. Неблокирующе «дождались» его завершения await'ом, разблокировали GUI. «Физически» такой код транслируется в цепочку обратных вызовов, выполняемую потоками из пула потоков и через диспетчер GUI-потока. Блокировку кнопок делается банально через команды.
Меня вот сильно интересует другой вопрос. С одной стороны WinRT очень сильно упрощает разработку сложных приложений, благодаря своей .net-подобной инфраструктуре. Однако с другой стороны модель жизненного цикла процесса и ограничения для WinRT-приложений плохо совместимы с «обычными» desktop приложениями, и в ряде случаев усложнят разработку.
Вопрос такой — а можно ли из Win32 приложения захостить WinRT-контент легальными способами? Т.е. встроить вывод WinRT на HWND сохранением интерактивности? Кто-нибудь этот вопрос пытался выяснить?
> Все подводные камни — в другом.

Собственно, в чем «в другом»? То что Вы описали — полностью соответствует Silverlight программированию, и парадигме, стоящей во главе угла — Песочнице. Меня порадовала Ваша цитата: «традиционный подход Microsoft — “сделать все хорошо, но что-нибудь наиболее часто используемое — плохо”, но в этом, конкретном, случае все вполне логично. Вы работаете в Песочнице, и у Вас нет никакого доступа к другим приложениям, кроме заранее определенных папок.

Все попытки всунуть Win32 контент и стили программирования в SL-окружение подобны требованию оснащать упряжью болид формулы — 1.
UFO just landed and posted this here
— библиотеки мне не нужны, у меня и так все мои террабайты неплохо отсортированы. :)
— поиск в проводнике — классная штука, но пользуюсь только в ситуации, когда в папке есть пара десятков гигабайт текстовых файликов, а надо найти один содержащий нужный текст, причем он там точно есть. Требуется это крайне редко.
— асинхронный код — хорошая штука, я только за! Просто они ж еще и все что смогли синхронного — тоже отобрали. Вот MessageBox им чем помешал-то, а? :) Сейчас — если я хочу приостановить работу программы пока пользователь с чем-то там не согласится — придется несколько функций дополнительно писать. Лишняя работа, которую могли бы за меня и разработчики фреймворка/студии сделать — хотя бы в виде Code Snippets.
>>библиотеки мне не нужны
Я вам открою страшную тайну, библиотеки не прибиты гвоздями, вполне можно в библотеки свои папки добавлять.

знаю :) Просто они неудобны в использовании, т.к. пользоваться ими можно было только в проводнике (и диалоговых окнах открытия/сохранения, что, впрочем, тот же проводник и есть). Учитывая сколько по времени запускался проводник, а так же удобство работы в нем без использования мыши (для скорости) — ну, вообщем, с библиотеками у меня не сложилось. Хотя идея хороша, да.
А сейчас все вообще просто — или ты используешь библиотеки, или ты идёшь нафиг не используешь какую-то часть из метро-приложений :)
UFO just landed and posted this here
Sign up to leave a comment.

Articles