Winforms вызов асинхронного метода зависает программа
Я работал над этой проблемой некоторое время, но теперь я действительно хотел бы понять, что идет не так. У меня довольно простое приложение (это плагин Turtoise SVN для youtrack, но я могу воспроизвести проблему с помощью тривиального приложения winforms).
У меня есть асинхронный метод ResolveIssue
public async Task<bool> ResolveIssue(Issue issue, int revision, string[] pathList)
{
await Task.Delay(1000);
return true;
}
Все, что мне нужно сделать, чтобы создать тупик, это вызвать этот асинхронный метод в Button
обработчик события и вызов Task.Wait
или же Task.Result
, как это
private void buttonOk_Click(object sender, System.EventArgs e)
{
var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList);
if (asyncResolvedIssue.Result) {} // <== deadlock!
}
Теперь я понимаю, что довольно странно иметь асинхронный метод и активно его ждать, но с какой стати это может привести к тупику?!
1 ответ
Ваша проблема в том, что вы блокируете поток пользовательского интерфейса при вызове .Result
а ты сказал продолжение после Task.Delay
работать в потоке пользовательского интерфейса. Таким образом, вы блокируете пользовательский интерфейс в ожидании выполнения задачи, которая блокируется в ожидании освобождения пользовательского интерфейса - классический тупик.
Два решения. Сначала нажмите кнопку асинхронно.
private async void buttonOk_Click(object sender, System.EventArgs e)
{
var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList);
if (await asyncResolvedIssue) {} // <== no deadlock!
}
Обработчики событий - это единственное место, которое вам разрешено делать async void
,
Другой вариант - сказать Task.Delay
ему не нужно запускать остальную часть своей функции в потоке пользовательского интерфейса, установив ConfigureAwait(bool)
ложно.
public async Task<bool> ResolveIssue(Issue issue, int revision, string[] pathList)
{
await Task.Delay(1000).ConfigureAwait(false);
return true;
}
Теперь строка кода после Task.Delay
будет работать в потоке потоков вместо потока пользовательского интерфейса и не будет заблокирован тем, что поток пользовательского интерфейса в настоящее время заблокирован.