Я не понимаю что это, как работает и в каких случаях используется. Может кто-нибудь по-русски объяснить?
Этот метод возвращает специальное значение, предназначенное для передечи оператору await и в отрыве от этого оператора не имеющее смысла.
Конструкция же await Task.Yield() делает довольно простую вещь - прерывает текущий метод и сразу же планирует его продолжение в текущем контексте синхронизации.
Используется же эта конструкция для разных целей.
Во-первых, эта конструкция может быть использована для немедленного возврата управления вызывающему коду. Например, при вызове из обработчика события событие будет считаться обработанным.
Во-вторых, эта конструкция используется для очистки синхронного контекста вызова. Например, так можно "закрыть" текущую транзакцию (ambient transaction):
using (var ts = new TransactionScope()) {
// ...
Foo();
// ...
ts.Complete();
}
async void Foo() {
// ... тут мы находимся в контексте транзакции
if (Transaction.Current != null) await Task.Yield();
// ... а тут его уже нет!
}
В-третьих, эта конструкция может очистить стек вызовов. Это может быть полезным если программа падает с переполнением стека при обработке кучи вложенных продолжений.
Например, рассмотрим упрощенную реализацию AsyncLock:
class AsyncLock
{
private Task unlockedTask = Task.CompletedTask;
public async Task<Action> Lock()
{
var tcs = new TaskCompletionSource<object>();
await Interlocked.Exchange(ref unlockedTask, tcs.Task);
return () => tcs.SetResult(null);
}
}
Здесь поступающие запросы на получение блокировки выстраиваются в неявную очередь на продолжениях. Казалось бы, что может пойти не так?
private static async Task Foo()
{
var _lock = new AsyncLock();
var unlock = await _lock.Lock();
for (var i = 0; i < 100000; i++) Bar(_lock);
unlock();
}
private static async void Bar(AsyncLock _lock)
{
var unlock = await _lock.Lock();
// do something sync
unlock();
}
Здесь продолжение метода Bar вызывается в тот момент, когда другой метод Bar выполняет вызов unlock(). Получается косвенная рекурсия между методом Bar и делегатом unlock, которая быстро сжирает стек и ведет к его переполнению.
Добавление же вызова Task.Yield()
перенесет исполнение в "чистый" фрейм стека, и ошибка исчезнет:
class AsyncLock
{
private Task unlockedTask = Task.CompletedTask;
public async Task<Action> Lock()
{
var tcs = new TaskCompletionSource<object>();
var prevTask = Interlocked.Exchange(ref unlockedTask, tcs.Task);
if (!prevTask.IsCompleted)
{
await prevTask;
await Task.Yield();
}
return () => tcs.SetResult(null);
}
}
Кстати, альтернативный способ починить код выше - использование флага RunContinuationsAsynchronously:
class AsyncLock
{
private Task unlockedTask = Task.CompletedTask;
public async Task<Action> Lock()
{
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
await Interlocked.Exchange(ref unlockedTask, tcs.Task);
return () => tcs.SetResult(null);
}
}
В-четвертых, при использовании в UI-потоке эта конструкция позволяет обработать накопившиеся события ввода-вывода, что полезно при длительных обновлениях интерфейса.
Например, при добавлении миллиона строк в таблицу программа не будет реагировать на действия пользователя пока все строки не будут добавлены. Но если, к примеру, после добавления каждой тысячи строк вставлять вызов await Task.Yield()
- программа сможет обрабатывать действия пользователя и не будет выглядеть зависшей.
В WinForms для тех же целей можно было использовать метод Application.DoEvents()
- но его избыточное использование приводило к переполнению стека. await Task.Yield()
- это универсальный способ, который можно использовать как в WinForms, так и в WPF.
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Нужно, чтобы при нажатии на button появлялась panel поверх всех компонентовPanel должна быть чёрного цвета и полупрозрачная
Здравствуйте, задача написать регулярное выражение для выборки данных следующим образом: в результате должны остаться правильные IP-адреса...
Собственно есть listview, как сделать сортировку по данным в столбцах? Есть столбец процессов - нужно по нажатию на колонку, сделать сортировку...
При запуске проекта появляется окно со следующей ошибкой "ошибка при попытке определить идентификатор процесса dotnetexe", запускаю на IIS в 17 студии