Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
Rammal
0 / 0 / 1
Регистрация: 10.01.2014
Сообщений: 18
1

Проблемы с конструкцией async\await при использовании WPF или Windows Forms

29.03.2014, 23:47. Просмотров 1446. Ответов 4
Метки нет (Все метки)

Добрый день!

Написал библиотечку, использующую, в том числе конструкции async-await. Всё работает, при компиляции в виде консольного приложения, выполняется на ура.

Подключил библиотечку к WPF-проекту, пытаюсь использовать (там, собственно, обращение к одному методу)... и наблюдаю зависание. Смотрю: где затык. Оказывается вот где:

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
...
foreach (XElement rootElement in rootElements.Elements())
    PartsParser(rootElement.Name.LocalName, rootElement.Elements());
...
 
private async void PartsParser(string partName, IEnumerable<XElement> partElements)
{
            _inWorkList.Add(partName);
            int count = 0;
            switch (partName)
            {
                ...
                case "Trade":
                    count = await TradeAsync(partElements);
                    break;
                case "WorldOutlooks":
                    count = await WorldAsync(partElements);
                    break;
                case "Buildings":
                    count = await BuildingAsync(partElements);
                    break;
                ...
            }
            Log("Заголовки раздела " + partName + " загружены (" + count + " шт.)";
            _inWorkList.Remove(partName); // используется для синхронизации потоков.
        }
Поясняю:
1. Некий метод обращается к асинхронному методу, который выбирает - что именно асинхронно прочитать в XDocument. Под каждый part этого XDocument имеется свой асинхронный метод.
2. Например, TradeAsync это:

C#
1
2
3
4
5
6
7
8
9
private async Task<int> TradeAsync(IEnumerable<XElement> partElements) 
         return await Task.Run(() =>
            {
                int count = 0;
                foreach (XElement subPartElement in partElements)
                ...
                return count;
            });
        }
3. Затык оказывается в методе PartsParser. Если быть точным, то команды после await не выполняются и до синхронизирующего исключения из List никогда не доходят. Я только начал разбираться с async-await. И вроде как написано, что после завершения потока, команды в методе, который асинхронно вызывал другой метод с await - должны бы выполнятся. И они выполняются, если это не WPF или WinForms.

Вопрос в следующем: почему?
Также происходит и с WinForms. Подключаю библиотеку, запускаю... наблюдаю, что команды после await не исполняются... Подскажите - в чем проблема? Что я упускаю?

Заранее благодарю.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.03.2014, 23:47
Ответы с готовыми решениями:

Async/await или разница между 2 методами
Добрых времени суток. Есть асинхронный метод: public Task&lt;List&lt;Address&gt;&gt; GetAllByStreet(string...

Windows Forms или WPF?
Добрый день! У меня есть необходимость написать некую корпоративную CRM систему для нужд...

Используют ли сейчас Windows Forms или все перешли на WPF?
Используют ли сейчас windows forms или все перешли на wpf? Насколько я знаю то винформы очень...

Async, await
Объясните работу async, await. Облазил весь интернет, но ничего толкового не нашел. Заранее...

Использование async/await
пытался написать такой тестовый код: нифига не работает, я видимо что-то неправильно делаю. Что...

4
Jupiter
Каратель
Эксперт С++
6576 / 3997 / 400
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
30.03.2014, 02:10 2
лишний await:
C#
1
2
3
4
5
6
7
8
9
private Task<int> TradeAsync(IEnumerable<XElement> partElements) 
         return Task.Run(() =>
            {
                int count = 0;
                foreach (XElement subPartElement in partElements)
                ...
                return count;
            });
        }
так код выглядит чище:
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
private async void PartsParser(string partName, IEnumerable<XElement> partElements)
{
            _inWorkList.Add(partName);
            Func<IEnumerable<XElement>, Task<int>> f = null;
 
            switch (partName)
            {
                ...
                case "Trade":
                    f = TradeAsync;
                    break;
                case "WorldOutlooks":
                    f = WorldAsync;
                    break;
                case "Buildings":
                    f = BuildingAsync;
                    break;
                ...
            }
 
            int count = await f(partElements);            
            Log("Заголовки раздела " + partName + " загружены (" + count + " шт.)";
            _inWorkList.Remove(partName); // используется для синхронизации потоков.
        }
0
Rammal
0 / 0 / 1
Регистрация: 10.01.2014
Сообщений: 18
30.03.2014, 14:27  [ТС] 3
Увы, до команд:

C#
1
2
Log("Заголовки раздела " + partName + " загружены (" + count + " шт.)";
_inWorkList.Remove(partName); // используется для синхронизации потоков.
Всё равно не доходит. Чет я нихрена не понимаю.
Т.е. поток не исключается из _inWorkList, соответственно синхронизация потоков вида

C#
1
2
3
while (_inWorkList.Count > 0)
            {
            }
... уходит в бесконечность.

Что интересно: все потоки отрабатывают, т.е. если поставить break point на конце async-метода, результат в виде количества прочтенных заголовков можно наблюдать. Но вот возврата этого значения вызывавшему главному потоку не происходит

Добавлено через 14 минут
И ещё вот что интересно. И что меня особенно смущает. Если поставить break point на int count = await f(partElements) (за совет по большей чистоте кода спасибо отдельное).... то иногда (заметьте, иногда!) выполнение доходит до строки Log("Заголовки раздела " + partName + " загружены (" + count + " шт.)". Причем всегда разных разделов.

И ни сообщений об ошибках, ни каких-то предупреждений... вообще ничего. Я не понимаю.

Добавлено через 1 час 28 минут
Экспериментальным путем выяснилось, что проблема не имеет отношения к тому, где находится код - в DLL или нет. Причем, при отладке DLL, если запустить как Консольное приложение или как Приложение Windows - всё выполняется быстро и легко. Даже если присоединить библиотеку к консольному приложению - тоже всё выполняется легко. А вот WPF или WinForms - проблема.

Добавлено через 48 минут
Эксперименты продолжаются. Вот это, в частности, работает. Почему аналогичное не работает в другой ситуации - не понятно. Отличия, собственно, минимальные: это прямо в коде UI, а исходное - в отдельном классе отдельной DLL.

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 4; i++)
                Parter(i);
        }
 
        private async void Parter(int i)
        {
            string rrr = "ooopps";
            switch (i)
            {
                case 0:
                    rrr = await DoWork0();
                    break;
                case 1:
                    rrr = await DoWork1();
                    break;
                case 2:
                    rrr = await DoWork2();
                    break;
                case 3:
                    rrr = await DoWork3();
                    break;
 
            }
            Debug.Print("Chunk " + rrr);
        }
 
 
        private Task<string> DoWork0()
        {
            return Task.Run(() =>
            {
                Thread.Sleep(2500);
                return "zero";
            });
        }
 
        private Task<string> DoWork1()
        {
            return Task.Run(() =>
            {
                Thread.Sleep(500);
                return "one";
            });
        }
 
        private Task<string> DoWork2()
        {
            return Task.Run(() =>
            {
                Thread.Sleep(5000);
                return "two";
            });
        }
 
        private Task<string> DoWork3()
        {
            return Task.Run(() =>
            {
                Thread.Sleep(500);
                return "three";
            });
        }
0
Jupiter
Каратель
Эксперт С++
6576 / 3997 / 400
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
30.03.2014, 14:38 4
выложите что ли проект, чтоб можно было запустить и проверить
0
Rammal
0 / 0 / 1
Регистрация: 10.01.2014
Сообщений: 18
30.03.2014, 14:41  [ТС] 5
Чьерт!!! Удалив мою "синхронизацию" потоков в виде

C#
1
while (_inWorkList.Count > 0) { }
Всё заработало! Я имею ввиду исходный вариант. Следовательно, правильно ли я понимаю - вопрос в неправильной синхронизации, которая осуществляется из главного потока. Т.е. главный поток что-то там блокирует и не позволяет остальным потокам...))

Т.е. у меня вызов метода в библиотеке происходил из основного потока UI (допустим, нажатием клавиши), затем он блокировался синхронизацией... и в ней почему-то оставался, не позволяя другим потокам закончить работу. Выход я вижу в следующем - запустить вообще всё выполнение в библиотеке в отдельном потоке... Как-то так.

Подскажите, кто понимает в чем моя ошибка. Заранее благодарю.

Цитата Сообщение от Jupiter Посмотреть сообщение
выложите что ли проект, чтоб можно было запустить и проверить
Увы, не имею права. За нами следят)))
0
30.03.2014, 14:41
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.03.2014, 14:41

Понимание потоков и async await
Всем привет, хочу задать пару вопросов опытным программистам: 1)Что такое потоки ? как они...

Async/await различия методов
В чем разница между AsyncWork1/2/3 private async void btnStart_Click_1(object sender, EventArgs...

Пауза через async/await
Написал процедуру Пауза на C# с помощью async/await, но почему-то не работает. Вот код: private ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru