Jak utworzyć metodę asynchroniczną w C#?
Każdy wpis na blogu, który przeczytałem, mówi ci, jak korzystać z metody asynchronicznej w C#, ale z jakiegoś dziwnego powodu nigdy nie wyjaśnia, jak zbudować własne metody asynchroniczne do konsumpcji. Więc mam teraz ten kod, który pochłania moją metodę:
private async void button1_Click(object sender, EventArgs e)
{
var now = await CountToAsync(1000);
label1.Text = now.ToString();
}
A ja napisałem tą metodę, która jest CountToAsync
:
private Task<DateTime> CountToAsync(int num = 1000)
{
return Task.Factory.StartNew(() =>
{
for (int i = 0; i < num; i++)
{
Console.WriteLine("#{0}", i);
}
}).ContinueWith(x => DateTime.Now);
}
Czy to, użycie Task.Factory
, jest najlepszym sposobem na napisanie metody asynchronicznej, czy powinienem napisać to w inny sposób?
2 answers
Nie polecam StartNew
chyba, że potrzebujesz takiego poziomu złożoności.
Jeśli twoja metoda asynchroniczna jest zależna od innych metod asynchronicznych, najprostszym podejściem jest użycie słowa kluczowego async
:
private static async Task<DateTime> CountToAsync(int num = 10)
{
for (int i = 0; i < num; i++)
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
return DateTime.Now;
}
Jeśli twoja metoda asynchroniczna wykonuje pracę procesora, powinieneś użyć Task.Run
:
private static async Task<DateTime> CountToAsync(int num = 10)
{
await Task.Run(() => ...);
return DateTime.Now;
}
You may find my async
/await
intro pomocne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-17 15:30:59
Jeśli nie chcesz używać async/wait wewnątrz metody, ale nadal "ozdobić" ją tak, aby móc używać słowa kluczowego wait z zewnątrz, TaskCompletionSource.cs:
public static Task<T> RunAsync<T>(Func<T> function)
{
if (function == null) throw new ArgumentNullException(“function”);
var tcs = new TaskCompletionSource<T>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
T result = function();
tcs.SetResult(result);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
Aby wspierać taki paradygmat zadaniami, potrzebujemy sposobu na zachowanie funkcji Zadania i możliwości odwoływania się do arbitralnej operacji asynchronicznej jako zadania, ale do kontrolowania żywotności tego zadania zgodnie z regułami podstawowego infrastruktury, która zapewnia asynchroniczność, i zrobić to w sposób, który nie kosztuje znacząco. To jest cel TaskCompletionSource.
I saw jest również używany w źródle. NET np. WebClient.cs:
[HostProtection(ExternalThreading = true)]
[ComVisible(false)]
public Task<string> UploadStringTaskAsync(Uri address, string method, string data)
{
// Create the task to be returned
var tcs = new TaskCompletionSource<string>(address);
// Setup the callback event handler
UploadStringCompletedEventHandler handler = null;
handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadStringCompleted -= completion);
this.UploadStringCompleted += handler;
// Start the async operation.
try { this.UploadStringAsync(address, method, data, tcs); }
catch
{
this.UploadStringCompleted -= handler;
throw;
}
// Return the task that represents the async operation
return tcs.Task;
}
Wreszcie, znalazłem przydatne również następujące:
Zadają mi to pytanie cały czas. Implikacja jest taka, że gdzieś musi być jakiś wątek, który blokuje wywołanie I / O do zewnętrznego zasobu. Kod asynchroniczny zwalnia wątek żądania, ale tylko kosztem innego wątku w innym systemie, prawda? Nie, wcale nie. Aby zrozumieć, dlaczego asynchroniczne żądania skalują się, prześledzę (uproszczony) przykład asynchronicznego wywołania We/Wy. Załóżmy, że żądanie wymaga zapisu do pliku. Wątek żądania wywołuje metodę zapisu asynchronicznego. WriteAsync jest zaimplementowany przez bibliotekę klas bazowych (BCL) i używa portów dopełnienia dla asynchronicznych wejść / wyjść. asynchroniczny zapis pliku. System operacyjny komunikuje się ze stosem sterowników, przekazując dane do zapisu w pakiecie I/O request packet (IRP). W tym miejscu robi się ciekawie: jeśli sterownik urządzenia nie może obsługiwać IRP natychmiast, musi obsługiwać go asynchronicznie. Tak więc sterownik mówi dyskowi, aby rozpoczął zapis i zwraca odpowiedź "oczekującą" do systemu operacyjnego. System operacyjny przekazuje tę" oczekującą " odpowiedź do BCL, a BCL zwraca niekompletne zadanie do kodu obsługi żądań. Kod obsługi żądania oczekuje zadania, które zwraca niekompletne zadanie z tej metody i tak dalej. Wreszcie kod obsługi żądania kończy się zwrotem niekompletnego zadania do ASP.NET, a wątek żądania jest zwolniony, aby powrócić do puli wątków.
Wprowadzenie do Async / ASP.NET
Jeśli celem jest poprawa skalowalności (a nie responsywności), wszystko zależy od istnienia zewnętrznego wejścia/wyjścia, które daje taką możliwość.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-03 19:45:13