Yanıtlar:
Eğer kullandığınız zaman async
/ await
, sen bunu yaptığında çağrı yöntemi hiçbir garantisi yoktur await FooAsync()
aslında uyumsuz çalışacaktır. Dahili uygulama tamamen senkronize bir yol kullanarak geri dönmekte serbesttir.
Engellememenizin kritik olduğu bir yerde API oluşturuyorsanız ve bazı kodları eşzamansız olarak çalıştırıyorsanız ve çağrılan yöntemin senkronize olarak (etkin bir şekilde engelleme) çalışma olasılığı varsa, kullanmak await Task.Yield()
yönteminizi eşzamansız olmaya ve geri dönmeye zorlar o noktada kontrol. Kodun geri kalanı geçerli bağlamda daha sonra çalıştırılacaktır (bu noktada yine de eşzamanlı olarak çalışabilir).
Bu, bazı "uzun süre çalışan" başlatma gerektiren asenkron bir yöntem yaparsanız da yararlı olabilir, yani:
private async void button_Click(object sender, EventArgs e)
{
await Task.Yield(); // Make us async right away
var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later
await UseDataAsync(data);
}
Task.Yield()
Çağrı olmadan, yöntem ilk çağrıya kadar senkronize olarak yürütülür await
.
Task.Run
uygulamak için a kullanırsanız ExecuteFooOnUIThread
, UI iş parçacığında değil iş parçacığı havuzunda çalışır. İle await Task.Yield()
, sonraki kod hala geçerli bağlamda çalışacak şekilde eşzamansız olmaya zorlarsınız (sadece daha sonraki bir noktada). Normalde yapacağınız bir şey değildir, ancak garip bir nedenden dolayı seçenek olması güzel.
ExecuteFooOnUIThread()
çok uzun süre çalışsaydı, hala bir noktada UI iş parçacığını uzun süre engeller ve kullanıcı arayüzünü yanıt vermez, doğru mu?
Dahili olarak, await Task.Yield()
basitçe ya mevcut senkronizasyon bağlamına veya rastgele bir havuz parçacığı üzerinde devam sıralar, eğer SynchronizationContext.Current
olduğunu null
.
Bu edilir verimli uygulanan özel awaiter olarak. Aynı etkiyi üreten daha az verimli bir kod bu kadar basit olabilir:
var tcs = new TaskCompletionSource<bool>();
var sc = SynchronizationContext.Current;
if (sc != null)
sc.Post(_ => tcs.SetResult(true), null);
else
ThreadPool.QueueUserWorkItem(_ => tcs.SetResult(true));
await tcs.Task;
Task.Yield()
bazı garip yürütme akış değişiklikleri için kısayol olarak kullanılabilir. Örneğin:
async Task DoDialogAsync()
{
var dialog = new Form();
Func<Task> showAsync = async () =>
{
await Task.Yield();
dialog.ShowDialog();
}
var dialogTask = showAsync();
await Task.Yield();
// now we're on the dialog's nested message loop started by dialog.ShowDialog
MessageBox.Show("The dialog is visible, click OK to close");
dialog.Close();
await dialogTask;
// we're back to the main message loop
}
Yani, w / uygun görev zamanlayıcı Task.Yield()
ile değiştirilemez hiçbir durumda düşünemiyorum Task.Factory.StartNew
.
Ayrıca bakınız:
var dialogTask = await showAsync();
?
var dialogTask = await showAsync()
derleme yapılmaz çünkü await showAsync()
ifade bir döndürmez Task
(await
). Bununla birlikte, bunu await showAsync()
yaptıktan sonra yürütme, yalnızca iletişim kapatıldıktan sonra sürdürülecektir, bu farklıdır. Bunun nedeni window.ShowDialog
senkronize bir API olmasıdır (yine de mesajları pompalamasına rağmen). Bu kodda, iletişim kutusu hala gösterilirken devam etmek istedim.
Bunun bir kullanımı, Task.Yield()
zaman uyumsuz özyineleme yaparken yığın taşmasını önlemektir. Task.Yield()
eşzamanlı devam etmeyi önler. Bununla birlikte, bunun bir OutOfMemory istisnasına neden olabileceğini unutmayın (Triynko tarafından belirtildiği gibi). Sonsuz özyineleme hala güvenli değildir ve özyinelemeyi bir döngü olarak yeniden yazmanız daha iyi olur.
private static void Main()
{
RecursiveMethod().Wait();
}
private static async Task RecursiveMethod()
{
await Task.Delay(1);
//await Task.Yield(); // Uncomment this line to prevent stackoverlfow.
await RecursiveMethod();
}
await Task.Delay(1)
önlemek için yeterli gibi görünüyor . (Konsol Uygulaması, .NET Core 3.1, C # 8)
Task.Yield()
asenkron yöntemlerin sahte uygulamalarında kullanılabilir.
await Task.Yield()
kuvvetlerin zaman uyumsuz olması yöntem, neden "gerçek" zaman uyumsuz kod yazarken rahatsız olur? Ağır bir senkronizasyon yöntemi düşünün. Zaman uyumsuz hale getirmek için, eklemekasync
veawait Task.Yield()
başlangıçta ve sihirli bir şekilde, zaman uyumsuz olacak? Bu hemen hemen tüm senkronizasyon kodunu içine almakTask.Run()
ve sahte bir async yöntemi oluşturmak gibi bir şeydir.