Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
Есть Web-сервис, на C#, работает под IIS. Возникли проблемы - понадобилось выводить в файл (для отсылки в стороннюю поддержку) данные. Реализовал примерно так:
Т.е. программа доходит до myFunc, выполняет её, и движется дальше. Всё работает, претензий ко мне нет. Но меня грызёт червь перфекционизма - можно же сделать лучше, можно же сделать асинхронно. Указал
но этого явно не достаточно. Что ещё надо доделать? Исправлено 3 раз(а). Последнее : S-type, 26.05.17 16:15 |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
Вот так удалось заставить работать:
Это корректный код? |
Re: Асинхронность | |
---|---|
Igor Korolyov Автор Сообщений: 34580 Дата регистрации: 28.05.2002 |
Да, насколько я понимаю ------------------ WBR, Igor |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
Это будет моя первая асинхронная функция... В понедельник поставлю "на бой".
|
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
Всё работает, вот теперь только осталось разобраться - как. Точнее - с какого именно места начинается асинхронность? С момента вызова функции myFuncAsync (функция опИсана как async), или с момента вызова fileStream.WriteAsync (вызов с помощью await)?
Исправлено 1 раз(а). Последнее : S-type, 27.05.17 17:29 |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
На сколько понимаю, можно сделать так:
выведет:
Выходит, асинхронность начинается с вызова fileStream.WriteAsync. Тогда совсем не понятен смысл - зачем объявлять функцию ключевым словом async. Компилятор без него функцию не даёт откомпилировать. В чём смысл? Исправлено 2 раз(а). Последнее : S-type, 27.05.17 18:28 |
Re: Асинхронность | |
---|---|
Igor Korolyov Автор Сообщений: 34580 Дата регистрации: 28.05.2002 |
Вот это изучить - зачитать до дыр
Асинхронность "начинается" с использования async в определении метода. Одного этого уже достаточно, чтобы система скомпилировала данный метод как state-машину (а не как простой, ординарный метод). И, если возвращаемый тип метода будет Task или Task<T>, то ЕГО уже можно будет "вызывать асинхронно". await внутри тела такого метода задаёт "точки приостановки". Т.е. по сути делит метод на части - каждая из которых будет скомпилирована в отдельный "шаг" state-машины. Если await нет, то и точек приостановки нет, и никакой реальной асинхронности не получится. Самая первая из них определяет (грубо говоря) где метод начнёт работать асинхронно - а точнее где метод вернёт управление в вызывающий код, передав тому объект Task (или его generic версию, если метод должен вернуть какое-то значение). Этот объект Task служит для того чтобы вызывающий метод мог спокойно продолжать работать, а в нужный момент времени мог (если это необходимо) дождаться завершения асинхронного метода и получить его возвращаемое значение. По твоему коду: Нужно совершенно чётко представлять, что из метода myFuncAsync ты "вывалишься" в вызывающий метод вовсе не после записи файла и печатания "Сохранение завершено", а ПЕРЕД этим - сразу же после Console.WriteLine("Ещё какие то действия"); А строка "Продолжаем" может и вовсе не вывестись - например если вызов myFuncAsync стоит сразу же в Main, а после него нет ничего полезного, или занимающего время ожидания (типа того же Console.ReadKey()) По хорошему этот метод должен возвращать тип Task, а в вызывающем его методе (не async - тот же Main в тесте) нужно применять нечто типа
Тогда хотя-бы есть гарантия что мы дождёмся завершения его работы. Иначе - ну может так произойти, что процесс завершится ещё до того как завершились все подобные "асинхронные" методы. Сам то процесс записи мне не удалось "прервать", а вот добиться того что не печатается "Продолжаем" и не создаётся файлик-флажок простейшим кодом
Даже при размере записываемого массива "всего" в 10кб значительная часть запусков проходила так, что "продолжения" на которое поделил await метод myFuncAsync не успевало сработать... Как я понимаю, в твоём изначальном примере такой проблемы нет, т.к. там нет ничего после await - никаких "продолжений"... Но я не силён в этих новых фишках, потому и написал более осторожно без гарантии того что это абсолютно правильный код Всё же более безопасно, я полагаю, сделать этот myFuncAsync возвращающим Task, а в Main таки гарантированно дожидаться его завершения. Именно по выше изложенной схеме с task.Wait(); т.к. сам Main нельзя делать async А то ещё и с проверкой статуса отработки Task-а, и отловом потенциально возникающих в нём исключений (если он не ловит и не давит ВСЕ возможные исключения, как у тебя в начальном примере - ну и если твоя "запись в лог" сама по себе не может выкинуть исключения, что тоже бывает в реальной жизни ). ------------------ WBR, Igor |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
И действительно... Если убрать ReadLine и получится такой вот код: Программа отработает, файл sss.txt создаётся, но данных в файле нет - файл пустой! Т.е. всё, что после await (включая сохранение в файл) не успевает отработать!
Выходит, правильный код такой:
Исправлено 3 раз(а). Последнее : S-type, 28.05.17 20:53 |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
Спасибо. Это очень существенное дополнение. Полез читать теорию...
|
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
То есть это ещё один способ - как незаметно отстрелить себе ногу (как сделать глючный код). |
Re: Асинхронность | |
---|---|
Igor Korolyov Автор Сообщений: 34580 Дата регистрации: 28.05.2002 |
Да. Но справедливости ради - соорудить КОРРЕКТНЫЙ асинхронный код без подобных "упрощателей" сможет очень небольшое число разработчиков. А так - посреди работающей программы даже не совсем аккуратное обращение с асинхронными методами вряд ли приведёт к катастрофическим последствиям
------------------ WBR, Igor |
Re: Асинхронность | |
---|---|
Igor Korolyov Автор Сообщений: 34580 Дата регистрации: 28.05.2002 |
Спросил у коллег - так "с возмущением" сказали что выгнали б с собеседования того кто применяет async void а не async Task
Хотя и сами не могут точно ответить на кучу вопросов возникающих при, скажем так, не совсем аккуратном использовании многопоточности вообще, и этой самой "асинхронности" в частности Т.е. async await это паттерн - определённая реализация идеи средствами компилятора и вспомогательных классов - но он САМ требует использования определённого паттерна при написании кода ------------------ WBR, Igor |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
Вот, нарисовал схему вызовов.
[attachment 27760 sss1.png] Правильно? |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
Это понятно, это речь о Task-based Asynchronous Pattern (TAP) msdn.microsoft.com А это не понятно - о каком ещё паттерне идёт речь? |
Re: Асинхронность | |
---|---|
Igor Korolyov Автор Сообщений: 34580 Дата регистрации: 28.05.2002 |
О том как правильно использовать эти async/await. А там куча разных нюансов есть... ------------------ WBR, Igor |
Re: Асинхронность | |
---|---|
S-type Сообщений: 2969 Дата регистрации: 24.04.2004 |
А как лучше делать:
или
Мне кажется, что второй вариант лучше в том плане, что переменная client не попадает в "замыкание". Или, всё равно, как делать? |
Re: Асинхронность | |
---|---|
Igor Korolyov Автор Сообщений: 34580 Дата регистрации: 28.05.2002 |
Мне кажется что без разницы. Всё одно ссылку на WebClient будет держать асинхронная реализация операции, так что от "лишней" ссылки в классе state-машины вреда я не вижу...
А в общем случае между созданием WebClient и запуском асинхронной операции может быть ещё несколько команд настройки - "лепить" всё это в одну строку как-то не очень красиво будет... Кстати, и ПОСЛЕ запуска DownloadStringTaskAsync вполне может быть ещё какой-то код, например что-то делающий со скачанной строкой и возвращающий уже результат после обработки... ------------------ WBR, Igor |
© 2000-2024 Fox Club  |