На этот вопрос трудно ответить, поскольку он сравнивает яблоки с апельсинами, утверждает, что они являются фруктами, и пытается сравнить их друг с другом.
1) Почему первый использует пул потоков ивторой нет? **
2) Почему второй дает вам масштабируемость, а первый нет - это связано с пулами потоков?
По умолчанию типы TPL , такие как Task
и Task<TResult>
, используют потоки пула потоков для запуска задач.SleepAsyncA
запускает задачу, затем вызывает Thread.Sleep
, которая ничего не делает, но блокирует текущий поток на определенный период времени.В результате все, что вы сделали, это сделали таймер, украдя поток пула потоков и блокируя его, пока вы не закончите.Очевидно, что если вы сохраняете этот масштабированный масштаб, у вас закончатся потоки пула потоков.
SleepAsyncB
работает с таймером.System.Threading.Timer
отправляет обратный вызов в потоке пула потоков вместо создания нового потока каждый раз.В этом случае он просто устанавливает результат на TaskCompletionSource
на мгновение.
Тип TaskCompletionSource<TResult>
служит двум связанным целям: это источник для создания задачи и источник для завершения этой задачи.A TaskCompletionSource<TResult>
выступает в качестве производителя для Task<TResult>
и его завершения.В отличие от задач, созданных Task.Run
и т. П., Task
, выданный TaskCompletionSource<TResult>
, не имеет ни одного запланированного делегата, связанного с ним, однако предоставляет методы, позволяющие контролировать время жизни и завершение связанной задачи.
По сути, вы берете шаблон события, созданный Timer
, и используете TaskCompletionSouce
, чтобы заставить его действовать как Task
.Тайм-аут не блокирует ни одного потока, поэтому он более масштабируемый.
3) Как вызвать два метода в main, чтобы сделать ихЦель более очевидна (и лучше подчеркнуть их различия)?
Учитывая
public static string DebugInfo
{
get
{
ThreadPool.GetMaxThreads(out var maxThreads, out _);
ThreadPool.GetAvailableThreads(out var threads, out _);
var usedThreads = maxThreads - threads;
var mt = $"{usedThreads.ToString().PadLeft(4)}/{maxThreads.ToString().PadLeft(4)}";
return $"Threads {mt.PadRight(8)}";
}
}
public static Task SleepAsyncA(int millisecondsTimeout)
{
return Task.Run(() => { Console.WriteLine("SleepAsyncA " + DebugInfo); Thread.Sleep(millisecondsTimeout); });
}
public static Task SleepAsyncB(int millisecondsTimeout)
{
TaskCompletionSource<bool> tcs = null;
var t = new Timer(delegate { tcs.TrySetResult(true); }, null, -1, -1);
Console.WriteLine("SleepAsyncB " + DebugInfo);
tcs = new TaskCompletionSource<bool>(t);
t.Change(millisecondsTimeout, -1);
return tcs.Task;
}
Использование
var ms = 5000;
Console.WriteLine("Start " + DebugInfo);
var list = Enumerable.Range(0, 10).Select(x => SleepAsyncA(ms));
Task.WaitAll(list.ToArray());
var list2 = Enumerable.Range(0, 10).Select(x => SleepAsyncB(ms));
Task.WaitAll(list2.ToArray());
Вывод
Start Threads 0/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 8/2047
SleepAsyncA Threads 9/2047
SleepAsyncA Threads 10/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
SleepAsyncB Threads 0/2047
Полная демонстрация здесь
4) Я знаю асинхронные методы задачиможно вызывать с помощью await, а как насчет задач, в которых отсутствует асинхронность, подобных этим методам?
Конечно!и это общая схема, позволяющая избежать лишнего конечного автомата и обеспечивающая вам эффективность.Однако каждый раз, когда вы вызываете await
, ваш метод должен быть помечен как async
private static async Task Main(string[] args)
{
var ms = 5000;
await SleepAsyncA(ms);
await SleepAsyncB(ms);
}
Наконец, почему бы просто не сохранить все хлопоты и лишний код, а просто использовать Task.Delay(ms)
private static async Task Main(string[] args)
{
await Task.Delay(ms);
}
Масштабируемый, простой, без суеты.