Запускать asyn c функцию в фоновом потоке? - PullRequest
0 голосов
/ 01 марта 2020

Я работаю над проектом, который включает в себя сервер и клиент. Клиент каждую секунду отправляет UDP-пакет на сервер, и в соответствии с ответом сервера он может открыть TCP-соединение с сервером (и получить файлы с сервера), клиентская программа имеет GUI, что мне не нужно блокировать (сделано в WPF MVVM), а также проблематично c запустить асинхронную c функцию в конструкторе MainWindow, поскольку конструкторы не могут быть асинхронными c. Итак, мой вопрос, могу ли я и должен ли я запускать функции asyn c в фоновом потоке? Улучшает ли asyn c производительность, если он находится в фоновом потоке, я говорю о разнице между этими параметрами:

public MainWindow()
{
    InitializeComponent();
    DirectoryViewModel DirectoryVM = new DirectoryViewModel();
    this.DataContext = DirectoryVM;
    DirectoryVM.StartListen(); //Unwanted as constructor won't finish
}

К

public MainWindow()
{
    InitializeComponent();
    DirectoryViewModel DirectoryVM = new DirectoryViewModel();
    this.DataContext = DirectoryVM;
    Task.Run(DirectoryVM.StartListen()); //Possible but async might be faster
}

К

public MainWindow()
{
    InitializeComponent();
    DirectoryViewModel DirectoryVM = new DirectoryViewModel();
    this.DataContext = DirectoryVM;
    Task.Run(async () => await DirectoryVM.StartListenAsync()); //Is it faster than the second option?
}

Из того, что я видел, я не должен запускать asyn c код в фоновом потоке, как это, но почему? Разве это не быстрее, чем запуск кода syn c в фоновом потоке? Кроме того, я думаю, что это не очень отличается, но на моем сервере я создам постоянный работающий поток, который прослушивает tcp-соединения и отправляет файлы через него, должен ли я сделать функцию отправки файлов asyn c или нет?

Спасибо!

Ответы [ 2 ]

1 голос
/ 03 марта 2020

... нормально ли запускать метод asyn c в отдельном потоке ...

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

Хотя есть возможность раскрутить постоянно работающий слушатель periodi c, используя метод asyn c, это скорее против его цели.

Когда вы вызываете метод asyn c, вы ожидаете, что он будет завершен в течение разумного времени (отсюда и причина, по которой вы хотите его дождаться), но для этого может потребоваться достаточно много времени. В вашем случае вам следует явно запустить новую фоновую задачу или поток, что проверяет periodi c. Это может быть новый поток или, что лучше, новая задача (например, Task.Run).

Из того, что я видел, я не должен запускать асин c код в фоновом потоке, как этот , но почему?

Согласно вашим комментариям DirectoryVM.StartListen() запускает постоянно запущенное прослушивание, что не обязательно должно быть асин c. Если он не выполняет асинхронные c вызовы, это не что-то ожидаемое.

Разве это не быстрее, чем выполнение кода syn c в фоновом потоке?

Asyn c не о скорости, а о блокировке потоков. Не имеет значения, является ли поток передним или задним, использование асин c метода для операции ввода-вывода, например, вызов конечной точки http или отправка пакета UDP, всегда выгодно, если поток может делать другие вещи во время ожидания, или в противном случае блокировка этого потока может вызвать другие проблемы.

Кроме того, я думаю, это не сильно отличается, но на моем сервере я создам постоянный работающий поток, который прослушивает tcp-соединения и отправляет файлы через него, если Я делаю функцию отправки файла asyn c или нет?

Вы должны, если это выгодно. Смотрите предыдущую часть.

0 голосов
/ 03 марта 2020

Из того, что я видел, я не должен запускать asyn c код в фоновом потоке, как это, но почему?

Я не знаю ни одной рекомендации не делать запускать асинхронный код с Task.Run.

Task.Run следует избегать на ASP. NET (как для синхронного, так и для асинхронного кода), но здесь это не применимо, поскольку у вас есть GUI app.

Разве это не быстрее, чем выполнение кода syn c в фоновом потоке?

Нет. Код не будет быстрее. async - это освобождение потоков, а не их ускорение.

Я думаю, что вы видели проблему игнорирования задач. Использование Task.Run и игнорирование возвращаемой задачи проблематично c, потому что это форма «забей и забудь». Так что, если ваш l oop не удастся из-за исключения, ваше приложение никогда не узнает. Одним из способов решения этой проблемы является await задача из метода async void. Например, в качестве обработчика событий вашего окна Initialized:

async void Window_Initialized(object, EventArgs)
{
  await Task.Run(DirectoryVM.StartListen);
  // or, if asynchronous:
  await DirectoryVM.StartListenAsync();
}
...