Блокируется UI при использовании async-await C#

297
04 апреля 2017, 08:53

Есть форма с button и Label. При нажатии на кнопку выполняется метод button1_Click:

    private async void button1_Click(object sender, EventArgs e)
    {
        // Список IP адресов.
        List<string> ListIP = new List<string>();
        // Метод getListPC(timeout) возвращает список ip адресов.
        ListIP = getListPC(50);
        // WMI-Класс, который позволяет получать информацию о ПК по IP:
        // Имя, процессор, материнская плата, список установленных программ и др.
        WMI current = new WMI();
        foreach (string el in ListIP)
        {
            label3.Text = el;
            // CheckАccess(IP) - метод класса WMI, позволяет проверить доступность ПК.
            await current.CheckАccess(el);
        }
    }

Код класса WMI

class WMI
{
    Logger logger = LogManager.GetCurrentClassLogger();
    private ConnectionOptions Connection { get; set; } = new ConnectionOptions();
    public Task<bool> CheckАccess(string ComputerName)
    {
        try
        {
            ManagementObjectSearcher searcher =
                new ManagementObjectSearcher("\\\\" + ComputerName + "\\root\\CIMV2", "SELECT * FROM Win32_ComputerSystem");
            ManagementScope scope =
                new ManagementScope("\\\\" + ComputerName + "\\root\\CIMV2", Connection);
            scope.Connect();
            searcher.Scope = scope;
            searcher.Get();
            return Task.FromResult(true);
        }
        catch (Exception e)
        {
            //MessageBox.Show(e.Message);
            logger.Trace(e.StackTrace + " " + e.Message);
            return Task.FromResult(false);
        }
    }
}

Во время подключения к ПК scope.Connect() в экземпляре класса WMI происходит блокировка UI. Почему это происходит? Разве перебор цикла foreach не должен быть продолжен без ожидания завершения метода CheckАccess?

Answer 1

Лучшим вариантом будет использование Task.Run, поскольку вы тогда явно укажете кодом, что хотите выполнять данный метод на потоке из ThreadPool, и что контекст UI вам в нем не интересен, и что это обертка над синхронным методом. Это если у классов ManagementObjectSearcher и ManagementScope нет асинхронных методов.

await Task.Run(()=>current.CheckАccess(el));
Answer 2

Тот факт, что метод CheckАccess возвращает Task и вы рядом с его вызовом написали await, не делает его асинхронным. Почитайте краткое изложение того, что делает async/await, посмотрите видео.

Проблема в том, что у вас весь метод CheckАccess выполняется синхронно. Варианта решения проблемы, как уже подсказали, два:

  1. Переписать вызов WMI в асинхронный вид, если это возможно.
  2. Обернуть вызов CheckАccess или вызов WMI самого CheckАccess в Task.Run().
READ ALSO
Возможен ли асинхронный сервер RabbitMQ?

Возможен ли асинхронный сервер RabbitMQ?

Рассмотрел шаблон работы RabbitMQ(RPC) принцип работы описан тутКак я понял единственная возможность как то распараллелить обработку запросов...

256
Экземпляр класса в свойстве класса php

Экземпляр класса в свойстве класса php

Только начал изучать ООП на phpПоявилась необходимость создать класс для работы с файлами и архивами

261
Как установить возможности htaccess?

Как установить возможности htaccess?

Есть phpini, есть htaccess

302