Блокирует не сама задача, а вызов Result
. Task
представляет собой асинхронную операцию, но вызов ее свойства Result
или вызов Wait()
заблокирует текущий поток до тех пор, пока метод не вернется. И во многих случаях это приведет к взаимоблокировке, потому что задача не может быть завершена с заблокированным вызывающим потоком!
Чтобы этого не произошло, свяжите задачи асинхронно, используя async
и await
.
private async void button1_Click(object sender, EventArgs e)
{
var result = await HeavyWorkAsync(); // <=== await
richTextBox1.AppendText(result);
}
Кроме того, Task.Delay(10).Wait();
полностью противоречит цели использования задач в первую очередь: это заблокирует текущий поток. Если это действительно то, что вы хотите сделать (а это довольно маловероятно), позвоните Thread.Sleep(10);
вместо этого, это сделает ваши намерения более ясными, и у вас будет меньше препятствий, через которые нужно прыгать. Или лучше используйте await Task.Delay(10);
in асинхронный метод.
О ConfigureAwait
Что именно делает ConfigureAwait(false)
?
Это устраняет обязательство продолжения выполнения задачи в том же контексте, что и вызывающая сторона задачи. В большинстве случаев это означает, что выполнение продолжения в том же контексте больше не гарантируется. Итак, если у меня есть метод, который делает Foo()
, немного ждет, а затем Bar()
, как этот:
async Task DoStufAsync()
{
Foo();
await Task.Delay(10);
Bar(); // run in the same context as Foo()
}
Я гарантирую, что Bar будет работать в том же контексте. Если бы у меня было ConfigureAwait(false)
, это уже не так
async Task DoStufAsync()
{
Foo();
await Task.Delay(10).ConfigureAwait(false);
Bar(); // can run on another thread as Foo()
}
Когда вы используете ConfigureAwait(false)
, вы говорите своей программе, что не возражаете против контекста. Это может решить некоторые проблемы взаимоблокировки, но обычно не является правильным решением. Вероятнее всего, правильное решение никогда не будет ждать задачи блокирующим образом и будет полностью асинхронным.
person
Falanwe
schedule
24.03.2015
await HeavyWorkAsync()
? - person thumbmunkeys   schedule 24.03.2015async void
является законным именно для такого случая. Да,async void
уродлив, и его следует избегать в каждой подписи, которая не является подпиской на событие, но у нас нет выбора, потому что используемая нами структура пользовательского интерфейса не поддерживает надлежащие асинхронные обратные вызовы. - person Falanwe   schedule 24.03.2015var result = HeavyWorkAsync().Result;
в потоке пользовательского интерфейса. - person thumbmunkeys   schedule 24.03.2015