Недавно я встретил пример дросселирования потоков для вызовов async/wait. После анализа и игры с кодом на моей машине я придумал несколько другой способ сделать то же самое. Что я сомневаюсь в том, что то, что происходит под капотом, почти одинаково или если есть какие-то тонкие различия, которые стоит отметить?
Здесь код, основанный на исходном примере:
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, и в результате получается немного более компактный. Является ли это точным или я отсюда без основания?