Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Asenkron yöntemler aşağıdaki dönüş türlerine sahip olabilir:
- Task, bir işlem gerçekleştiren ancak değer döndürmeyen zaman uyumsuz bir yöntem için.
- Eşzamansız bir yöntem için, bir değer döndüren Task<TResult>.
-
void
bir olay işleyicisi için. - Erişilebilir bir
GetAwaiter
metodu olan herhangi bir tür.GetAwaiter
yöntemi tarafından döndürülen nesnenin System.Runtime.CompilerServices.ICriticalNotifyCompletion arabirimini uygulaması gerekir. - zaman uyumsuz bir akışdöndüren bir zaman uyumsuz yöntem için
.
Zaman uyumsuz yöntemler hakkında daha fazla bilgi için bkz. async ve await (C#) ile zaman uyumsuz programlama .
Windows iş yüklerine özgü başka türler de vardır:
- Windows ile sınırlı eşzamansız işlemler için DispatcherOperation.
- IAsyncAction, Evrensel Windows Platformu (UWP) uygulamalarında değer döndürmeyen asenkron eylemler için.
- IAsyncActionWithProgress<TProgress>, UWP uygulamalarında ilerleme durumunu bildiren ancak değer döndürmeyen eşzamansız eylemler için.
- bir değer döndüren UWP uygulamalarında zaman uyumsuz işlemler için IAsyncOperation<TResult>.
- IAsyncOperationWithProgress<TResult,TProgress>, UWP uygulamalarında ilerleme durumunu raporlayan ve bir değer döndüren asenkron işlemler için.
Görev dönüş türü
return
deyimi içermeyen veya işlenen döndürmeyen bir return
deyimine sahip olan zaman uyumsuz yöntemler genellikle Taskdönüş tipine sahiptir. Bu tür yöntemler zaman uyumlu olarak çalıştırılırsa void
döndürür. Zaman uyumsuz bir yöntem için Task dönüş türü kullanırsanız, çağıran yöntem, çağrılan zaman uyumsuz yöntem bitene kadar çağıranın tamamlanmasını askıya almak üzere bir await
işleci kullanabilir.
Aşağıdaki örnekte, WaitAndApologizeAsync
yöntemi bir return
deyimi içermediğinden, yöntem bir Task nesnesi döndürür.
Task
döndürülerek WaitAndApologizeAsync
beklenebilir.
Task türü, dönüş değeri olmadığından bir Result
özelliği içermez.
public static async Task DisplayCurrentInfoAsync()
{
await WaitAndApologizeAsync();
Console.WriteLine($"Today is {DateTime.Now:D}");
Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}");
Console.WriteLine("The current temperature is 76 degrees.");
}
static async Task WaitAndApologizeAsync()
{
await Task.Delay(2000);
Console.WriteLine("Sorry for the delay...\n");
}
// Example output:
// Sorry for the delay...
//
// Today is Monday, August 17, 2020
// The current time is 12:59:24.2183304
// The current temperature is 76 degrees.
WaitAndApologizeAsync
, senkron void döndüren metot için çağrı ifadesine benzer bir await ifadesi yerine await deyimi kullanılarak beklenir. Bu durumda await işlecinin kullanılması bir değer üretmez. Bir await
'ın sağ işleneni bir Task<TResult>olduğunda, await
ifadesi T
sonucunu verir. Ne zaman bir await
’ın sağ işleneni bir Taskise, await
ve onun işleneni bir deyimi oluşturur.
Aşağıdaki kodda gösterildiği gibi, WaitAndApologizeAsync
çağrısını await işlecinin uygulamasından ayırabilirsiniz. Ancak, bir Task
'ın Result
özelliği olmadığını ve await operatörü bir Task
'ye uygulandığında değer üretilmediğini unutmayın.
Aşağıdaki kod, WaitAndApologizeAsync
yöntemini çağırmayı yöntemin döndürdüğü görevi beklemesinden ayırır.
Task waitAndApologizeTask = WaitAndApologizeAsync();
string output =
$"Today is {DateTime.Now:D}\n" +
$"The current time is {DateTime.Now.TimeOfDay:t}\n" +
"The current temperature is 76 degrees.\n";
await waitAndApologizeTask;
Console.WriteLine(output);
Görev<TResult> dönüş türü
Task<TResult> dönüş türü, işlenenin olduğu TResult
deyimini içeren eşzamansız bir yöntem için kullanılır.
Aşağıdaki örnekte, GetLeisureHoursAsync
yöntemi tamsayı döndüren bir return
deyimi içerir. Yöntem bildirimi, Task<int>
dönüş türünü belirtmelidir.
FromResult zaman uyumsuz yöntemi, DayOfWeekdöndüren bir işlem için yer tutucudur.
public static async Task ShowTodaysInfoAsync()
{
string message =
$"Today is {DateTime.Today:D}\n" +
"Today's hours of leisure: " +
$"{await GetLeisureHoursAsync()}";
Console.WriteLine(message);
}
static async Task<int> GetLeisureHoursAsync()
{
DayOfWeek today = await Task.FromResult(DateTime.Now.DayOfWeek);
int leisureHours =
today is DayOfWeek.Saturday || today is DayOfWeek.Sunday
? 16 : 5;
return leisureHours;
}
// Example output:
// Today is Wednesday, May 24, 2017
// Today's hours of leisure: 5
GetLeisureHoursAsync
yöntemindeki bir await ifadesinin içinden ShowTodaysInfo
çağrıldığında, await ifadesi leisureHours
yöntemi tarafından döndürülen görevde depolanan tamsayı değerini (GetLeisureHours
değeri) alır. await ifadesiyle ilgili daha detaylı bilgi almak için bkz. await.
Aşağıdaki kodun gösterdiği gibi, await
çağrısını Task<T>
uygulamasından ayırarak, GetLeisureHoursAsync
'ın await
sonucunu nasıl elde ettiğini daha iyi anlayabilirsiniz. Henüz beklenmeyen bir yöntem GetLeisureHoursAsync
çağrısı, yöntemin bildiriminden bekleneceği üzere bir Task<int>
döndürür. Görev örnekteki getLeisureHoursTask
değişkenine atanır.
getLeisureHoursTask
bir Task<TResult>olduğundan, Resulttüründe bir TResult
özelliği içerir. Bu durumda, TResult
bir tamsayı türünü temsil eder.
await
getLeisureHoursTask
'e uygulandığında, await ifadesi Result'ün getLeisureHoursTask
özelliğinin içeriği ile eşleşir. Değer ret
değişkenine atanır.
Önemli
Result özelliği bir engelleme özelliğidir. Görevin tamamlanması sona ermeden önce erişmeye çalışırsanız, şu anda aktif olan thread görev tamamlanana ve değer elde edilene kadar bloke olur. Çoğu durumda, özelliğine doğrudan erişmek yerine await
kullanarak değere erişmeniz gerekir.
Önceki örnek, Result yönteminin uygulama sona ermeden önce Main
'yi konsola yazdırabilmesi için ana iş parçacığını engelleyen message
özelliğinin değerini aldı.
var getLeisureHoursTask = GetLeisureHoursAsync();
string message =
$"Today is {DateTime.Today:D}\n" +
"Today's hours of leisure: " +
$"{await getLeisureHoursTask}";
Console.WriteLine(message);
Geçersiz dönüş türü
void
dönüş türünü, void
dönüş türü gerektiren zaman uyumsuz olay işleyicilerinde kullanırsınız. Değer döndürmeyen olay işleyicileri dışındaki yöntemler için bunun yerine bir Task döndürmelisiniz çünkü void
döndüren zaman uyumsuz bir yöntem beklenemez. Böyle bir yöntemi çağıranlar, çağrılan eşzamansız yöntemin bitmesini beklemeden işlemlerini tamamlamalıdır. Çağıran, zaman uyumsuz yöntemin oluşturduğu herhangi bir değerden veya özel durumdan bağımsız olmalıdır.
Void döndüren bir async yöntemi çağıran kişi, yöntem tarafından atılan özel durumları yakalayamaz. Bu tür işlenmeyen özel durumlar uygulamanızın başarısız olmasına neden olabilir. Task veya Task<TResult> döndüren bir yöntem özel durum oluşturursa, özel durum döndürülen görevde depolanır. Görev beklenirken özel durum yeniden oluşturulur. Özel durum oluşturabilen herhangi bir asenkron yöntemin Task veya Task<TResult> dönüş türüne sahip olduğunu ve yöntem çağrılarının beklendiğinden emin olun.
Aşağıdaki örnek, zaman uyumsuz olay işleyicisinin davranışını gösterir. Örnek kodda, zaman uyumsuz bir etkinlik işleyicisi bittiğinde bunu ana iş parçacığına bildirmesi gerekir. Ardından ana iş parçacığı, programdan çıkmadan önce bir zaman uyumsuz olay işleyicisinin tamamlanmasını bekleyebilir.
public class NaiveButton
{
public event EventHandler? Clicked;
public void Click()
{
Console.WriteLine("Somebody has clicked a button. Let's raise the event...");
Clicked?.Invoke(this, EventArgs.Empty);
Console.WriteLine("All listeners are notified.");
}
}
public class AsyncVoidExample
{
static readonly TaskCompletionSource<bool> s_tcs = new TaskCompletionSource<bool>();
public static async Task MultipleEventHandlersAsync()
{
Task<bool> secondHandlerFinished = s_tcs.Task;
var button = new NaiveButton();
button.Clicked += OnButtonClicked1;
button.Clicked += OnButtonClicked2Async;
button.Clicked += OnButtonClicked3;
Console.WriteLine("Before button.Click() is called...");
button.Click();
Console.WriteLine("After button.Click() is called...");
await secondHandlerFinished;
}
private static void OnButtonClicked1(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 1 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 1 is done.");
}
private static async void OnButtonClicked2Async(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 2 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 2 is about to go async...");
await Task.Delay(500);
Console.WriteLine(" Handler 2 is done.");
s_tcs.SetResult(true);
}
private static void OnButtonClicked3(object? sender, EventArgs e)
{
Console.WriteLine(" Handler 3 is starting...");
Task.Delay(100).Wait();
Console.WriteLine(" Handler 3 is done.");
}
}
// Example output:
//
// Before button.Click() is called...
// Somebody has clicked a button. Let's raise the event...
// Handler 1 is starting...
// Handler 1 is done.
// Handler 2 is starting...
// Handler 2 is about to go async...
// Handler 3 is starting...
// Handler 3 is done.
// All listeners are notified.
// After button.Click() is called...
// Handler 2 is done.
Genelleştirilmiş zaman uyumsuz dönüş türleri ve ValueTask<TResult>
Zaman uyumsuz yöntem,bir GetAwaiter
yönteminden döndürülen tür System.Runtime.CompilerServices.AsyncMethodBuilderAttribute özniteliğine sahip olmalıdır. Derleyici
Bu özellik, beklenebilir ifadelerin tamamlayıcısıdır ve, await
işleneninin gereksinimlerini açıklar. Genelleştirilmiş zaman uyumsuz dönüş türleri, derleyicinin farklı türler döndüren async
yöntemler oluşturmasını sağlar. Genelleştirilmiş zaman uyumsuz dönüş türleri .NET kitaplıklarında performans geliştirmelerini etkinleştirdi.
Task ve Task<TResult> başvuru türleri olduğundan, özellikle de ayırmalar sıkı döngülerde gerçekleştiğinde performans açısından kritik yollarda bellek ayırma performansı olumsuz etkileyebilir. Genelleştirilmiş dönüş türleri desteği, daha fazla bellek ayırmasını önlemek için başvuru türü yerine basit bir değer türü döndürebileceğiniz anlamına gelir.
.NET, genelleştirilmiş bir görev döndüren değerin basit bir uygulaması olarak System.Threading.Tasks.ValueTask<TResult> yapısını sağlar. Aşağıdaki örnek, iki zar atma işleminin değerini almak için ValueTask<TResult> yapısını kullanır.
class Program
{
static readonly Random s_rnd = new Random();
static async Task Main() =>
Console.WriteLine($"You rolled {await GetDiceRollAsync()}");
static async ValueTask<int> GetDiceRollAsync()
{
Console.WriteLine("Shaking dice...");
int roll1 = await RollAsync();
int roll2 = await RollAsync();
return roll1 + roll2;
}
static async ValueTask<int> RollAsync()
{
await Task.Delay(500);
int diceRoll = s_rnd.Next(1, 7);
return diceRoll;
}
}
// Example output:
// Shaking dice...
// You rolled 8
Genelleştirilmiş bir asenkron dönüş türü yazmak gelişmiş bir senaryodur ve özel ortamlarda kullanılmak üzere tasarlanmıştır. Bunun yerine Task
, Task<T>
ve ValueTask<T>
türlerini kullanmayı göz önünde bulundurun; bu, zaman uyumsuz koda yönelik çoğu senaryoyu kapsar.
Belirtilen türün oluşturucusunu geçersiz kılmak için AsyncMethodBuilder
özniteliğini zaman uyumsuz bir yönteme (zaman uyumsuz dönüş türü bildirimi yerine) uygulayabilirsiniz. Bu özniteliği genellikle .NET çalışma zamanında sağlanan farklı bir oluşturucuyu kullanmak için uygularsınız.
IAsyncEnumerable<T> ile eşzamansız akışlar
Bir zaman uyumsuz yöntem, zaman uyumsuz akışdöndürebilir ve bu, IAsyncEnumerable<T>tarafından temsil edilir. Asenkron bir akış, öğelerin tekrar eden asenkron çağrılarla öbekler halinde üretildiği durumlarda, bir akıştan okunan öğeleri listelemek için bir yol sağlar. Aşağıdaki örnek, eşzamansız bir akış üreten bir eşzamansız yöntemi göstermektedir.
static async IAsyncEnumerable<string> ReadWordsFromStreamAsync()
{
string data =
@"This is a line of text.
Here is the second line of text.
And there is one more for good measure.
Wait, that was the penultimate line.";
using var readStream = new StringReader(data);
string? line = await readStream.ReadLineAsync();
while (line != null)
{
foreach (string word in line.Split(' ', StringSplitOptions.RemoveEmptyEntries))
{
yield return word;
}
line = await readStream.ReadLineAsync();
}
}
Yukarıdaki örnek, bir dizedeki satırları asenkron olarak okur. Her satır okunduktan sonra, kod dizedeki her sözcüğü numaralandırır. Arayanlar, await foreach
deyimini kullanarak her sözcüğü numaralandırır. Yöntem, kaynak dizeden bir sonraki satırı eşzamanlı olmayan bir şekilde okuması gerektiğinde bekler.
Ayrıca bkz.
- FromResult
- Zaman uyumsuz görevleri tamamladıkça
- zaman uyumsuz ve await (C#) ile zaman uyumsuz programlama
- Asenkron
- bekliyor