Сторонний метод синхронизации, блокирующий пользовательский интерфейс в .NET 4.7.2 WPF - PullRequest
0 голосов
/ 27 мая 2019

У меня есть приложение .NET 4.7.2, использующее WPF MVVM. Я подключаюсь к роботу, используя предоставленную библиотеку от производителя. К сожалению, их метод, который подключается к роботу, останавливается на 30 секунд, когда параметр IP неверен, и это по существу замораживает пользовательский интерфейс.

Я решил использовать async / await для решения этой проблемы, основываясь на this Я подумал, что это проблема ввода-вывода, но поскольку метод, который я использую для подключения к роботу, - это синхронизация, Я не мог ждать этого. В примерах, которые я видел, они обычно использовали асинхронные библиотеки в первую очередь, и я не мог найти, как решить эту проблему, когда метод синхронизации, предоставленный сторонней организацией, замораживает мой пользовательский интерфейс.

Первый фрагмент кода не работал, мой интерфейс остановился на 30 секунд, когда я попытался подключиться.

public async Task<bool> ConnectToRobot(string ip = "")
        {
            if (FanucController.IsConnected)
                return true;

            var result = await ConnectToFanuc(ip);

            return result;
        }

private Task<bool> ConnectToFanuc(string ip)
        {
            try
            {
                ((IRobot)FanucController).Connect(ip);
                // Other code for connection

                return Task.FromResult(true);
            }
            catch
            {
                return Task.FromResult(false);
            }
        }

В конце концов я справился с этим, используя пример с привязкой к ЦП (второй фрагмент кода), однако на самом деле это не проблема, связанная с ЦП, поэтому я не уверен, что это вызовет проблемы в будущем.

public async Task<bool> ConnectToRobot(string ip = "")
        {
            if (FanucController.IsConnected)
                return true;

            var result = await Task.Run(() => ConnectToFanuc(ip));

            return result;
        }

private bool ConnectToFanuc(string ip)
        {
            try
            {
                ((IRobot)FanucController).Connect(ip);
                // Other code for connection

                return true;
            }
            catch
            {
                return false;
            }
        }

Есть ли лучший способ решить эту проблему? Должен ли я использовать что-то кроме ключевых слов async / await?

Ответы [ 2 ]

1 голос
/ 27 мая 2019

Я думаю, вы совершенно не поняли, что делает .net async.

Task<T> является реализацией монады Promise.

Это может быть в разных состояниях (очень просто).

  • Не завершено
  • В комплекте с результатом
  • Завершено с ошибкой

Вот как асинхронный / ожидающий движок делает свое волшебство. Методы могут "завершаться" без результата.

Task.FromResult создает Обещание во 2-м состоянии. Это означает, что у асинхронного / ожидающего движка нет шансов выключиться и сделать что-то еще в ожидании результата.

Одной из проблем с .net async await framework является проблема "Turtles / Async all the down". Для того чтобы асинхронное ожидание работало должным образом, вам нужно все, чтобы использовать новую скрытую реализацию асинхронных задач / задач (что является болью, поскольку в целом это означает повторную реализацию всей библиотеки снова).

Для быстрого решения этой проблемы используйте Task.Run. Это приемлемый обходной путь для сторонних библиотек, которые не поддерживают async / await.

0 голосов
/ 27 мая 2019

Использование Task.Run для создания асинхронных оболочек вокруг синхронных методов обычно считается плохой практикой, если только вы не хотите разгрузить текущий поток, чтобы предотвратить его зависание во время ожидания завершения синхронного метода.

Таким образом, поскольку ConnectToFanuc, очевидно, не является асинхронным в этом случае, целесообразно использовать await Task.Run для его вызова.

Пожалуйста, обратитесь к этому блогу для получения дополнительной информации об этом.

...