Недавно я наткнулся на пример дросселирования потоков для вызовов async/await. После анализа и игры с кодом на моей машине я придумал несколько другой способ сделать то же самое. Что я не уверен в том, что то, что происходит под капотом, почти одинаково или если есть какие-то тонкие различия, которые стоит отметить?Семафорная дроссельная заслонка с асинхронным/ожиданием
Вот код, основанный на оригинальном примере:
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");
}
И вот мое взятие на том же коде:
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");
}
Я, вероятно, далеко, но кажется, как Task. Подход Run создает задачу для запуска LongRunningTask(), а затем добавляет продолжение для печати результата, тогда как мой подход обходит задачу, созданную Task.Run, и в результате становится немного более компактным. Является ли это точным или я отсюда?
спасибо. Это точно, что я ищу: побочные эффекты реализации, которые проскальзывают через трещины. Похоже, что есть много чего с асинхронным ожиданием. Я буду работать над обработкой исключений. Я знаком с AggregateException от TPL, но с этим недостаточно справился. – AFM
Это на самом деле больше случай остатков от TPL, которые - очень редко - полезны с 'async', но чаще, чем просто мешают. Например, конструктор 'Task',' Start', 'Wait',' Result', 'ContinueWith',' WaitAll' и 'WaitAny' предназначены для * параллельного * (не * асинхронного *) программирования, и его следует избегать в мир 'async', если вы действительно не знаете, что делаете. –