Niedawno natknąłem się na przykład dławienia wątków dla połączeń asynchronicznych/oczekujących. Po analizie i graniu z kodem na moim komputerze, wymyśliłem nieco inny sposób robienia tego samego. Nie jestem pewien, czy to, co dzieje się pod maską, jest takie samo, czy też warto zwrócić uwagę na subtelne różnice?Ograniczanie wątków semaforowych z asynchronicznym/oczekiwanym
Oto kod na podstawie oryginalnego przykład:
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5);
public async Task CallThrottledTasks()
{
var tasks = new List<Task>();
for (int count = 1; count <= 20; count++)
{
await _semaphore.WaitAsync();
tasks.Add(Task.Run(async() =>
{
try
{
int result = await LongRunningTask();
Debug.Print(result.ToString());
}
finally
{
_semaphore.Release();
}
}));
}
await Task.WhenAll(tasks);
Debug.Print("Finished CallThrottledTasks");
}
A oto moje zdanie na ten sam kod:
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5);
public async Task CallThrottledTasks()
{
var tasks = new List<Task>();
for (int count = 1; count <= 20; count++)
{
await _semaphore.WaitAsync();
tasks.Add(LongRunningTask().ContinueWith(t =>
{
try
{
int result = t.Result;
Debug.Print(result.ToString());
}
finally
{
_semaphore.Release();
}
}));
}
await Task.WhenAll(tasks);
Debug.Print("Finished CallThrottledTasks");
}
Jestem chyba daleko, ale wydaje się to zadanie. Podejście do uruchamiania polega na utworzeniu zadania do uruchamiania funkcji LongRunningTask(), a następnie dodaje kontynuację drukowania wyniku, podczas gdy moje podejście pomija zadanie utworzone przez Task.Run i jest w rezultacie nieco bardziej szczupłe. Czy to jest dokładne, czy też jestem poza bazą?
Dziękuję. Jest to dokładnie to, czego szukam: efekty uboczne wdrożenia, które prześlizgują się przez szczeliny. Wygląda na to, że jest dużo tego z oczekiwaniem. Zrobię trochę pracy nóg, w jaki sposób traktowane są wyjątki. Jestem zaznajomiony z AggregateException z TPL, ale nie miałem wystarczająco dużo rąk do tego. – AFM
Jest to w rzeczywistości więcej przypadków resztek z licencji TPL, które są - bardzo rzadko - przydatne w przypadku "asynchronizowania", ale częściej wchodzą w drogę. Np. Konstruktor 'Task',' Start', 'Wait',' Result', 'ContinueWith',' WaitAll' i 'WaitAny' są przeznaczone do * równoległego * (nie * asynchronicznego *) programowania i powinny być unikane w świat "asynchroniczny", chyba że naprawdę wiesz, co robisz. –