powered by simpleCommunicator - 2.0.56     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / await,async и TASK - не получается.
25 сообщений из 25, страница 1 из 1
await,async и TASK - не получается.
    #38449170
Monochromatique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Понимаю, что позорно,заблудился в трех словах, но ведь и на самом деле не выходит.

Есть метод

Код: c#
1.
2.
3.
4.
public String someStringFromServer()
{
//Здесь надо спросить вебсервер и вернуть то, что он прислал
}



Есть модный класс (какой-нибудь из httpClient или WebClient c Extensions), который имеет метод DownloadStringTaskAsync<String>() (кажется так)

Вопрос - как из метода, обозначенного выше вернуть строку, которую асинхронно возвращает ВебКлиент в виде задачи?

Я рыл инет - ловлю deadlock-и при любых раскладах. Пробовал и configureAwaits(false) и Wait() и пытался распространять асинхронность по всему коду (этот момент кстати не до конца понял). В примерах часто приводится код с использованием CTP - так он вообще не компилируется (await-ы в методах без async-ов)

В идеале хочется, не морозя UI получить ответ и дальше с ним работать. С помощью TPL я так понял это можно сделать. Но я не понимаю как.

Про распространение асинхронности - но ведь все равно когда-то придется получить результат. А результат у меня получить ни разу не удалось.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449175
beg-in-er
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Monochromatique,

что бы не заморачиваться , если есть доступ к серверу , то можно использовать WCF.
а метод someStringFromServer сделать асинхроным, в конце которого запустить событие окончания приёма.
на всё провсё 15-20 минут.

WCF по шагам годно описан в msdn. даже новичёк поймёт.

по шагам
или тут
тынц2
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449191
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Monochromatique,

вот как-то примерно так:

ваш UI

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
        private MyClient _client = new MyClient();
        private CancellationTokenSource _currentWork;
 
        private async void button1_Click(object sender, EventArgs e)
        {
            // что делать если задача ещё выполняется
            if (_currentWork != null)
            {
                // или отменить задачу, или показать сообщение или что-нибудь ещё
                return;
            }

            using (_currentWork = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
            {
                try
                {
                    var result = await _client.DoSomeAsync(_currentWork.Token));
                    // сделать что-нибудь с результатом
                }
                catch (TaskCanceledException)
                {
                    // выполнение задачи было отменено
                    ShowWarning(CommonMessages.Cancelled);
                }
                catch (Exception ex)
                {
                    ShowError(ex);
                }
                finally
                {
                    _currentWork = null;
                }
            }
        }



метод MyClient

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
        public async Task<string> DoSomeAsync(CancellationToken cancellationToken)
        {
            try
            {
                using (var http = new HttpClient())
                {
                    var response = await http.GetAsync(_hostUri, cancellationToken);
                    if (!response.IsSuccessStatusCode)
                    {
                        // обработка HTTP ошибки
                        return null;
                    }
                    var data = await resp.Content.ReadAsStringAsync();
                    return data;
                }
            }
            catch (HttpRequestException ex)
            {
                var webEx = ex.InnerException;
                if (webEx is WebException)
                {
                    // обработка WebException
                }
                return null;
            }
        }



таким образом нажатие на кнопку не приводит к блокировке UI, асинхронно приложение ломится куда-то там и что-то делает через HttpClient (полностью асинхронный клиент). работу можно отменить через CancellationTokenSource. ну и поменьше заморочек с контекcтом.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449228
Monochromatique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
beg-in-erMonochromatique,

что бы не заморачиваться , если есть доступ к серверу , то можно использовать WCF.
а метод someStringFromServer сделать асинхроным, в конце которого запустить событие окончания приёма.
на всё провсё 15-20 минут.

WCF по шагам годно описан в msdn. даже новичёк поймёт.

по шагам
или тут
тынц2

Нееее, доступа к веб-серверу нету. Наглухо.
Да и потом, webClient сам по себе имеет Async метод с событием по окончании. Так что WCF тут без нужды, но на совет спасибо.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449230
Monochromatique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttMonochromatique,

вот как-то примерно так:

ваш UI

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
        private MyClient _client = new MyClient();
        private CancellationTokenSource _currentWork;
 
        private async void button1_Click(object sender, EventArgs e)
        {
            // что делать если задача ещё выполняется
            if (_currentWork != null)
            {
                // или отменить задачу, или показать сообщение или что-нибудь ещё
                return;
            }

            using (_currentWork = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
            {
                try
                {
                    var result = await _client.DoSomeAsync(_currentWork.Token));
                    // сделать что-нибудь с результатом
                }
                catch (TaskCanceledException)
                {
                    // выполнение задачи было отменено
                    ShowWarning(CommonMessages.Cancelled);
                }
                catch (Exception ex)
                {
                    ShowError(ex);
                }
                finally
                {
                    _currentWork = null;
                }
            }
        }



метод MyClient

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
        public async Task<string> DoSomeAsync(CancellationToken cancellationToken)
        {
            try
            {
                using (var http = new HttpClient())
                {
                    var response = await http.GetAsync(_hostUri, cancellationToken);
                    if (!response.IsSuccessStatusCode)
                    {
                        // обработка HTTP ошибки
                        return null;
                    }
                    var data = await resp.Content.ReadAsStringAsync();
                    return data;
                }
            }
            catch (HttpRequestException ex)
            {
                var webEx = ex.InnerException;
                if (webEx is WebException)
                {
                    // обработка WebException
                }
                return null;
            }
        }



таким образом нажатие на кнопку не приводит к блокировке UI, асинхронно приложение ломится куда-то там и что-то делает через HttpClient (полностью асинхронный клиент). работу можно отменить через CancellationTokenSource. ну и поменьше заморочек с контекcтом.

Я правильно понимаю, что в вашем примере применен подход - " async повсюду"? И основное правило тут - async должен оканчиваться методом c возвратом void?
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449236
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MonochromatiqueЯ правильно понимаю, что в вашем примере применен подход - " async повсюду"? И основное правило тут - async должен оканчиваться методом c возвратом void?

в ином случае использование async бесмысленно. если вы хотите создать асинхронное приложение, т.е. чтобы работа в фоне не блокировало работу UI интерфейса (как вы говорите, не морозило), то вам придётся применить один из подходов для разработки асинхронных приложений. их есть несколько. async — самый простой на сегодняшний день.

async метод должен возвращать Task или Task<T>. возврат void это сахар.

если метод Method() возвращает Task<string>, то вот такой вызов:

var result = await Method();

в результате result сохранит string.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449348
Фотография МСУ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt async метод должен возвращать Task или Task<T>. возврат void это сахар.
Какой же это сахар, ты что. Классический пример с "void button1_Click". Но рекомендация MS гласит, что по возможности нужно возвращать Task.

http://msdn.microsoft.com/ru-ru/library/vstudio/hh524395.aspx Основное использование возвращаемого значения void (процедуры Sub в Visual Basic) — в обработчиках событий, где требуется возвращать значение типа void. Возврат void также можно использовать для переопределения возвращающих void методов или для методов, выполняющих действия, которые подчиняются принципу "отправить и забыть". Однако необходимо возвращать Task всегда, когда это возможно, поскольку асинхронные методы, возвращающие void, ожидать невозможно. Любой вызывающий объект такого метода должен иметь возможность продолжить работу до завершения, не дожидаясь завершения вызванного асинхронного метода, и он не должен зависеть ни от каких значений и исключений, создаваемых асинхронным методом.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449391
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
МСУ,

а ну я имел в виду, что Task в любом случае создается, только если использовать void он теряется. однако "сахар" потому что для button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task. исходников нет, чтобы посмотреть.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449396
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
у меня по ходу дела встречный вопрос возник

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
            using (_currentWork = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
            {
                try
                {
                    var result = await _client.DoSomeAsync(_currentWork.Token));
                    // сделать что-нибудь с результатом
                }
                catch (TaskCanceledException)
                {
                    // выполнение задачи было отменено
                    ShowWarning(CommonMessages.Cancelled);
                }
                catch (Exception ex)
                {
                    ShowError(ex);
                }
                finally
                {
                    _currentWork = null;
                }
            }



если вот так в finally обнулять используемое в using значение, не потеряется ли вызов Dispose ?
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449408
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttМСУ,

а ну я имел в виду, что Task в любом случае создается, только если использовать void он теряется. однако "сахар" потому что для button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task. исходников нет, чтобы посмотреть.

т.е. не в целом фреймворк, а конкретно WinForms. ему Task от обработчика события нужен, чтобы правильно завершить приложения, если юзер нажмёт на крестик в углу.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449441
Фотография МСУ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttдля button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task
Откуда информация о тасковых выковыриваниях?
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449488
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
МСУhVosttдля button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task
Откуда информация о тасковых выковыриваниях?

информации нет, я типо просто так утверждаю, на основе логических рассужденей. может и не выковыривает. тогда хз, что должно произойти при закрытии приложения, если в таске что-нибудь крутится. как винформс пошлёт мессадж в поток об экстренном завершении? или просто грохнет? я просто винформс не очень глубоко изучал. делаю иногда несложные утилиты для выковыривания и отображения данных из сервисов и БД. без асинка вообще ужас был, прям ненависть ненависть. а щас хорошо ))
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449780
Monochromatique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttМСУпропущено...

Откуда информация о тасковых выковыриваниях?

из сервисов и БД. без асинка вообще ужас был, прям ненависть ненависть. а щас хорошо ))

А в чем, пардон, ужас?
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38449907
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MonochromatiqueА в чем, пардон, ужас?

в бэкграундворкере и в ручном разруливании контекстов.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38450361
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MonochromatiqueВ идеале хочется, не морозя UI получить ответ и дальше с ним работать. С помощью TPL я так понял это можно сделать. Но я не понимаю как.
Для WPF можно задействовать Dispatcher.PushFrame
см. Samples for Parallel Programming Samples for Parallel Programming
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
    public static class WebClientExtensions
    {
        public static Task<string> DownloadStringTask(this WebClient webClient, Uri address)
        {
            TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
            DownloadStringCompletedEventHandler handler = null;
            handler = (sender, e) => WebClientExtensions.HandleCompletion(tcs, e, () => e.Result, () => webClient.DownloadStringCompleted -= handler);
            webClient.DownloadStringCompleted += handler;
            try {
                webClient.DownloadStringAsync(address, tcs);
            } catch (Exception exc) {
                webClient.DownloadStringCompleted -= handler;
                tcs.TrySetException(exc);
            }
            return tcs.Task;
        }
        public static void HandleCompletion<T>(
            TaskCompletionSource<T> tcs, AsyncCompletedEventArgs e, Func<T> getResult, Action unregisterHandler)
        {
            if (e.UserState == tcs) {
                if (e.Cancelled) tcs.TrySetCanceled();
                else if (e.Error != null) tcs.TrySetException(e.Error);
                else tcs.TrySetResult(getResult());
                unregisterHandler();
            }
        }
        public static void WaitWithPumping(this Task task)
        {
            if (task == null) throw new ArgumentNullException("task");
            var nestedFrame = new DispatcherFrame();
            task.ContinueWith(_ => nestedFrame.Continue = false);
            Dispatcher.PushFrame(nestedFrame);
            task.Wait();
        }
    }


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
        public String someStringFromServer()
        {
            //Здесь надо спросить вебсервер и вернуть то, что он прислал
            string result = null;
            (new WebClient()).DownloadStringTask(new Uri("http://www.sql.ru/forum/1056514/await-async-i-task-ne-poluchaetsya")).ContinueWith(task => {
                switch (task.Status) {
                    case TaskStatus.RanToCompletion:
                        result = task.Result;
                        break;
                    case TaskStatus.Faulted:
                        System.Diagnostics.Debug.WriteLine("Request failed: {0}", task.Exception.InnerException);
                        break;
                    case TaskStatus.Canceled:
                        System.Diagnostics.Debug.WriteLine("Request was canceled");
                        break;
                }
            }).WaitWithPumping();//.Wait();
            return result;
        }


...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38450509
Фотография LR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttесли вот так в finally обнулять используемое в using значение, не потеряется ли вызов Dispose ?
"Свою" переменную using не позволит обнулить, ведь он для того и придуман, чтобы гарантированно вызвать Dispose (т.е., обнулится переменная, объявленная выше using)
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38571571
Lamo2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Прицеплюсь к теме, чтобы не плодить новых.

Не понимаю деталей выполнения async методов, а точнее того, в каком потоке будет выполнятся "окончание" асинхронного метода (то, что ожидает результата вызова await и все после него). В букварях утверждают что окончание метода будет выполнено в потоке, который вызвал асинхронный метод. Однако или это не всегда так, или я люто туплю. Пожалуйста растолкуйте.

Есть форма с асинхронным методом:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Console.WriteLine("Start Form1 in thread {0}", Thread.CurrentThread.ManagedThreadId);
            btnCallMethod_Click(null, null);
            Console.WriteLine("End Form1 in thread {0}", Thread.CurrentThread.ManagedThreadId);
        }

        public async void btnCallMethod_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Start btnCallMethod_Click in thread {0}", Thread.CurrentThread.ManagedThreadId);
            var t = await DoWork();
            this.Text = t;
            Console.WriteLine("End btnCallMethod_Click in thread {0} with result {1}", Thread.CurrentThread.ManagedThreadId, t);
        }
        // See below for code walkthrough...
        public Task<string> DoWork()
        {
            return Task.Run(() =>
            {
                Console.WriteLine("Start DoWork in thread {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                Console.WriteLine("End DoWork in thread {0}", Thread.CurrentThread.ManagedThreadId);
                return "Done with work!";
            });
        }
    }


При ее запуске в InitializeComponent будет вызван btnCallMethod_Click (просто чтобы на кнопку не давить. по кнопке происходит то же самое), который является асинхронным методом. Строка
Код: c#
1.
 Console.WriteLine("End btnCallMethod_Click... 

будет выполнена после окончания работы метода DoWork в потоке, который вызвал btnCallMethod_Click (DoWork будет выполнен в другом потоке). Все в точности как по учебнику.

Однако если использовать консольное приложение со следующим кодом:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
public class Program
    {
        public Task<int> MyTask()
        {
            return Task.Run(() =>
            {
                Console.WriteLine("Start MyTask in thread {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                Console.WriteLine("End MyTask in thread {0}", Thread.CurrentThread.ManagedThreadId);
                return 5;
            });
        }

        public async void MyAsyncMethod(object sender, EventArgs e)
        {
            Console.WriteLine("Start MyAsyncMethod in thread {0}", Thread.CurrentThread.ManagedThreadId);
            var result = await MyTask();
            Console.WriteLine("End MyAsyncMethod in thread {0} with result {1}", Thread.CurrentThread.ManagedThreadId, result);
        }

        static void Main()
        {
            Console.WriteLine("Start Main in thread {0}", Thread.CurrentThread.ManagedThreadId);
            var p = new Program();
            p.MyAsyncMethod(null, null);
            Console.WriteLine("End Main in thread {0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadKey();
        }
    }


то строка
Код: c#
1.
Console.WriteLine("End MyAsyncMethod 

будет выполнена в потоке, который выполнял MyTask, т.е. отличном от того, в котором выполнялась строка
Код: c#
1.
Console.WriteLine("Start MyAsyncMethod

.
Почему так происходит?
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38572010
Lamo2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
up
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38572024
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38572204
Lamo2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Lelouch,

Суть в "По умолчанию используется текущий SynchronizationContext, т.е. если задача запущена из UI-потока, то продолжение будет тоже выполнено в UI потоке (по аналогии с Dispatcher.BeginInvoke). Если текущий sync-контекст пустой, то используется TaskScheduler.Current." ?
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38572214
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Lamo2012,

а где у вас в примере поток UI ?
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38572218
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Lamo2012,

проверьте значение SynchronizationContext.Current . Что то мне подсказывает, что оно пустое. Поток, в котором выполняется метод Main не имеет контекста синхронизации.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38572226
Lamo2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Lelouch,

Спасибо! Похоже дело именно в этом. Вот в этой статье вопрос планирования продолжений рассмотрен чуть более детально.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38572264
MsSql_Study
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Отвечая на вопрос Monochromatique из первого поста (будет полезно тем, кто потом случайно будет находить эту тему поиском), добавлю ссылки на эти 2 полезные статьи

http://blogs.msdn.com/b/pfxteam/archive/2009/06/09/9716439.aspx
http://msdn.microsoft.com/ru-ru/magazine/ff959203.aspx

В первой статье кратко, сжато (и сложно), а во второй полно, описан переход от старых моделей многопоточного программирования, к новой, с блэкджеком и Task'ами.

В частности рассмотрен метод Task.Factory.FromAsync позволяющий обернуть асинхронные Begin End в Task с последующем ожиданием в async.

Там еще много чего полезного.
...
Рейтинг: 0 / 0
await,async и TASK - не получается.
    #38574849
Monochromatique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Парни, а можно как-то незамороченно ловить исключения?

Каждую залипуху в других потоках надо специально ловить - код превращается черте-во-что.

Пока выяснил, почему не работает банальный LINQ2SQL - три блока пришлось расставить.
...
Рейтинг: 0 / 0
25 сообщений из 25, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / await,async и TASK - не получается.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]