Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
2288 / 1604 / 400
Регистрация: 26.06.2017
Сообщений: 4,757
Записей в блоге: 1

Получение результата асинхронной операции

08.12.2022, 11:56. Показов 772. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день.

Данная тема в продолжение этой темы.

В общем не понимаю, где споткнулся, но после запроса форма зависает наглохо.
Код формы
Кликните здесь для просмотра всего текста
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 partial class AForm : Form
  {
    public AForm()
    {
      InitializeComponent();
    }
 
    TestService tService;
 
    private void AForm_Load(object sender, EventArgs e)
    {
      tService = new TestService();
    }
 
    private void button1_Click(object sender, EventArgs e)
    {
      try
      {
        label1.Text = tService.TestGetR(1).ToString();
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message);
      }
    }
  }

Код класса TestService
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  public class TestService
  {
    private RRepository rRepo;
 
    public TestService() 
    {
      rRepo = new RRepository(); 
    }
 
    public RModel TestGetR(int id)
    {
      RModel r = rRepo.GetByIdAsync(id).Result; //← вот тут нет ожидания
      return r;
    }
  }

Код класса RRepository
Кликните здесь для просмотра всего текста
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
  public class RRepository;
 
    public RRepository() 
    {
     ... 
    }
 
    public async Task<RModel> GetByIdAsync(int id, CancellationToken cancelToken)
    {
      return await Task.Run(async () =>
      {
        RModel resultR = null;
        if (cancelToken.IsCancellationRequested)
        {
          return resultR;
        }
        else
        {
          using (DbConnection connection = baseRepo.GetDbConnection())
          {
            string query = $"SELECT * FROM [RTable] WHERE ID={id}";
            DbCommand selectCmd = baseRepo.DbFactory.CreateCommand();
            selectCmd.CommandText = query;
            selectCmd.CommandType = System.Data.CommandType.Text;
            selectCmd.Connection = connection;
 
            await connection.OpenAsync(cancelToken);
 
            using (DbDataReader reader = await selectCmd.ExecuteReaderAsync(cancelToken))
            {
              if (await reader.ReadAsync(cancelToken))
              {
                resultR = new RModel(reader.GetInt32(0), reader.GetInt32(1));
              }
              reader.Close();
            }
            connection.Close();
          }
          return resultR;
        }
      }, cancelToken);
    }
  }

Как получить значение из задачи?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.12.2022, 11:56
Ответы с готовыми решениями:

Отмена Асинхронной операции
Создал асинхронный метод, который внутри вызывает создание массива строк, затем заполняет DataGridView. Если в процессе создания массива...

Не срабатывает отмена асинхронной операции в BackgroundWorker
Здравствуйте! Пишу приложение для пингования доступности списка IP-адресов. на даный момент при нажатии кнопки Старт/Стоп, код которой...

SendMessage получение результата
Пытаюсь найти способ получать от запроса SendMessage Инициализирую функцию SendMessage так: public static extern int...

14
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
08.12.2022, 12:19
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    
    public async Task<RModel> TestGetR(int id)
    {
      RModel r = await rRepo.GetByIdAsync(id); //← вот тут нет ожидания
      return r;
    }
 
    private async void button1_Click(object sender, EventArgs e)
    {
      try
      {
        var result = await tService.TestGetR(1);
        label1.Text = result.ToString();
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message);
      }
    }
0
 Аватар для Andrey-MSK
3360 / 2246 / 388
Регистрация: 14.08.2018
Сообщений: 7,590
Записей в блоге: 4
08.12.2022, 12:42
Цитата Сообщение от Uswer Посмотреть сообщение
C#
1
return await Task.Run(async () =>
А зачем вот это, если в теле метода все вызовы через await?

И reader.Close() c connection.Close() при использовании их в using не надо... При выходе из видимости using - объекты уничтожаются и соединения разрываются.
0
2288 / 1604 / 400
Регистрация: 26.06.2017
Сообщений: 4,757
Записей в блоге: 1
08.12.2022, 13:19  [ТС]
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
А зачем вот это
Чтобы весь метод был асинхронным, а не только его отдельные вызовы.
kotelok, в чём принципиальное отличие этого (у меня)
C#
1
RModel r = rRepo.GetByIdAsync(id).Result;
от этого (у Вас)
C#
1
RModel r = await rRepo.GetByIdAsync(id);
?
В литературе написано, что в месте обращения к свойству Task.Result будет ожидание выполнения задачи и она выполняется, но результат, видимо, так и не возвращается в форму.
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
08.12.2022, 13:25
Лучший ответ Сообщение было отмечено Uswer как решение

Решение

Цитата Сообщение от Uswer Посмотреть сообщение
в чём принципиальное отличие этого
В том, что если использовать '.Result', UI-поток заблокируется до завершения операции.

Если 'await', то управление вернётся в UI-поток, операция выполнится асинхронно (хотя, там может зависеть от внутренней реализации), после чего отработает весь хвост метода, который идёт после асинхронного вызова (либо в UI-потоке, либо в другом, зависит от наличия контекста и явных указаний через GetAwaiter).

Добавлено через 3 минуты
Насколько помню, если делать ".Result" из UI-потока у которого есть контекст и у которого дефолтный 'GetAwaiter(true)' не переопределён, то UI-поток блокируется на время выполнения, а после завершения метода (т.к. true), остаток метода пытается выполниться в заблокированном UI-потоке (т.е. он ждёт, пока поток разблокируется, но поток разблокируется только когда тот ожидающий завершится). Результат - дедлок.
1
Эксперт .NET
 Аватар для Usaga
14314 / 9400 / 1355
Регистрация: 21.01.2016
Сообщений: 35,452
08.12.2022, 13:29
Цитата Сообщение от Uswer Посмотреть сообщение
return await Task.Run(async () =>
О_о

Добавлено через 22 секунды
Цитата Сообщение от Uswer Посмотреть сообщение
Чтобы весь метод был асинхронным, а не только его отдельные вызовы.
Что под этим понимать?)
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
08.12.2022, 13:29
Ну т.е. вы либо сделайте 'ConfigureAwait(false)', либо уберите Result/Wait().
0
 Аватар для Andrey-MSK
3360 / 2246 / 388
Регистрация: 14.08.2018
Сообщений: 7,590
Записей в блоге: 4
08.12.2022, 13:44
Цитата Сообщение от Uswer Посмотреть сообщение
Чтобы весь метод был асинхронным, а не только его отдельные вызовы.
У вас метод async, в нём вызываются асинхронные методы через await - какой еще полностью асинхронный метод?

Добавлено через 1 минуту
Uswer, Книжку вы видать не до конца прочитали...

Добавлено через 2 минуты
Uswer, Показываю еще раз Полностью асинхронный метод чтения из БД
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
public async Task<List<Country>> GetCountriesAsync()
{
    List<Country> countries = new List<Country>();
    string sqlText =
        "SELECT ID_HRDCountry, Country, IsForeigner " +
        "FROM dbo.tblHRDCountry " +
        "ORDER BY Country";
 
    try
    {
        using (SqlConnection sqlConnection = new SqlConnection(_connectionString))
        {
            await sqlConnection.OpenAsync();
 
            using (SqlCommand sqlCommand = new SqlCommand(sqlText, sqlConnection))
            {
                using (SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync())
                {
                    if (sqlDataReader.HasRows)
                    {
                        while (await sqlDataReader.ReadAsync())
                        {
                            countries.Add(new Country
                            {
                                CountryID = (int)sqlDataReader["ID_HRDCountry"],
                                Name = (string)sqlDataReader["Country"],
                                IsForeigner = (int)sqlDataReader["IsForeigner"]
                            });
                        }
                    }
                }
            }
        }
 
        return countries;
    }
    catch (Exception ex)
    {
        throw new ApplicationException("Ошибка загрузки списка стран.", ex);
    }
}
И вызов его вот такой
C#
1
List<Country> countries = await GetCountriesAsync();
1
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
08.12.2022, 14:29
Вот, нашёл, тут более подробно рассказано (в частности про дедлок в WF/WPF):
https://habr.com/ru/company/dododev/blog/435666/
0
2288 / 1604 / 400
Регистрация: 26.06.2017
Сообщений: 4,757
Записей в блоге: 1
08.12.2022, 15:16  [ТС]
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
Книжку вы видать не до конца прочитали
Толстая книжка однако!
Цитата Сообщение от Usaga Посмотреть сообщение
О_о
Я ошибку осознал
Так, хорошо, с вызовом разобрался. Подскажите пожалуйста как можно в классе реализовать функцию возвращающую значение, а не Task, при том, что внутри функции предполагаются асинхронные вызовы? То есть желательно чтобы данная функция вызывалась синхронно, но при этом сама использовала асинхрон, например:
C#
1
RModel r = rRepo.GetById(id); //← внутри GetById хочется использовать асинхронные вызовы
Добавлено через 2 минуты
Цитата Сообщение от kotelok Посмотреть сообщение
Вот, нашёл
Я тоже и прочитал и нашёл про синхронизацию.
0
 Аватар для Andrey-MSK
3360 / 2246 / 388
Регистрация: 14.08.2018
Сообщений: 7,590
Записей в блоге: 4
08.12.2022, 15:25
Цитата Сообщение от Uswer Посмотреть сообщение
То есть желательно чтобы данная функция вызывалась синхронно, но при этом сама использовала асинхрон, например:
Зачем? Я ведь вам показал вызов метода с возвращением значения...

Добавлено через 1 минуту
Цитата Сообщение от Uswer Посмотреть сообщение
C#
1
RModel r = rRepo.GetById(id);
C#
1
RModel r = await rRepo.GetByIdAsync(id);
Добавлено через 2 минуты
Uswer, Я же вам уже говорил, при использовании async/await ВСЕ вызовы СНИЗУ и ДОВЕРХУ - асинхронные. Самый последний метод, который в самом верху, с типом void.
0
2288 / 1604 / 400
Регистрация: 26.06.2017
Сообщений: 4,757
Записей в блоге: 1
08.12.2022, 15:41  [ТС]
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
Я же вам уже говорил
Я это понял.
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
Самый последний метод, который в самом верху, с типом void.
Воот, а хочется на верху иметь ФУНКЦИЮ.
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,768
08.12.2022, 15:45
Цитата Сообщение от Uswer Посмотреть сообщение
Подскажите пожалуйста как можно в классе реализовать функцию возвращающую значение, а не Task, при том, что внутри функции предполагаются асинхронные вызовы? То есть желательно чтобы данная функция вызывалась синхронно, но при этом сама использовала асинхрон
Зачем, чтобы заблокировать вызывающий поток на время выполнения асинхронного метода?

Создайте таск, которому на вход передайте метод, который возвращает таск, сконфигурируйте 'ConfigureAwait' в 'false', запросите 'awaiter', а у него результат.

Конфигурировать/запрашивать всё это у самого метода не очень удачная идея, т.к. внутри могут быть await-вызовы, которые этого не сделают, а потому упрутся в тот самый дедлок.

На базе старого примера. В данном случае, вызывающий поток будет заблокирован на 2 секунды, после чего получит результат:
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
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        DebugLog("Click started");
 
        //var result = DoSomeAsync().ConfigureAwait(false).GetAwaiter().GetResult();
        var result = Task.Run(DoSomeAsync).ConfigureAwait(false).GetAwaiter().GetResult();
 
        DebugLog("Click completed: " + result);
    }
 
    private async Task<int> DoSomeAsync()
    {
        DebugLog("Delay");
 
        //Тут нет ConfigureAwait(false), потому если в точке вызова использовать 
        //закомментированый вариант, будет тот самый дедлок при попытке пройти 
        //дальше этого Delay.
        await Task.Delay(1000);
 
        DebugLog("Sleep");
        Thread.Sleep(1000);
 
        DebugLog("End");
        return 42;
    }
 
    private void DebugLog(string msg)
    {
        Debug.WriteLine($"[{Environment.CurrentManagedThreadId}]: {msg}");
    }
0
 Аватар для Andrey-MSK
3360 / 2246 / 388
Регистрация: 14.08.2018
Сообщений: 7,590
Записей в блоге: 4
08.12.2022, 15:55
Цитата Сообщение от Uswer Посмотреть сообщение
Воот, а хочется на верху иметь ФУНКЦИЮ.
Вверху метод Main(), вот он и будет public static async void Main().

Добавлено через 1 минуту
Это если консольное приложение, в WF или WPF значения не имеет, там будет верхним методом обработчик события (WF) или команда (WPF).
0
2288 / 1604 / 400
Регистрация: 26.06.2017
Сообщений: 4,757
Записей в блоге: 1
08.12.2022, 16:14  [ТС]
kotelok, понятно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.12.2022, 16:14
Помогаю со студенческими работами здесь

Написать программу, обеспечивающую выбор пользователем математической операции и расчѐт результата
помогите с заданием 1. Создать форму и нанести на неѐ три элемента TextBox, один элемент ComboBox, одну кнопку. 2. На кнопку нанести...

Таймаут асинхронной операции
Добрый день! Хочу написать tcp-сервер с асинхронными операциями ввода-вывода (BeginReceive/EndReceive или async...

Ожидание асинхронной операции в событии
Проблема очевидна - дедлок из-за 'Result'. Как решать - не понятно. Суть - это именно синхронное событие. Оно должно блокировать...

Зависание окна при выполнении асинхронной операции
private void RenameTextBox_LostFocus(object sender, RoutedEventArgs e) { ...

Отображение результата логической операции
Только начал изучать c#. Попытался создать программу которая показывала результат логической операции например true&amp;&amp;true=true и...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru