не могли бы вы помочь мне понять разницу между двумя методами здесь:
1) почему первый использует пул потоков, а второй - нет?
2) Почему второй дает вам масштабируемость, а первый - нет - это связано с пулами потоков?
3) Как я могу вызвать два метода в основном, чтобы сделать их назначение более очевидным (и лучше осветить их различия)?
4) Я знаю, что методы async Task можно вызывать с помощью await, а как насчет задач, в которых отсутствует асинхронность, таких как эти методы?
public class _12_MyClass
{
public Task SleepAsyncA(int millisecondsTimeout)
{
return Task.Run(() => Thread.Sleep(millisecondsTimeout));
}
public Task SleepAsyncB(int millisecondsTimeout)
{
TaskCompletionSource<bool> tcs = null;
var t = new Timer(delegate { tcs.TrySetResult(true); }, null, -1, -1);
tcs = new TaskCompletionSource<bool>(t);
t.Change(millisecondsTimeout, -1);
return tcs.Task;
}
public static void Main()
{
}
}
да, Кеннет, это для C#
Этот вопрос ведет в кроличью нору





На этот вопрос сложно ответить, потому что он сравнивает яблоки с апельсинами, утверждает, что это фрукты, и пытается сравнить их друг с другом.
1) Why does the first use the thread pool and the second doesn't?**
2) Why does the second give you scalability, but the first doesn't - is this related to thread pools?
По умолчанию типы ОСАГО, такие как Task и Task<TResult>, используют потоки пула потоков для выполнения задач. SleepAsyncA запускает задачу, затем вызывает Thread.Sleep, который ничего не делает, кроме как блокирует текущий поток на определенный период времени. В результате все, что вы сделали, - это таймер, украв поток пула потоков и заблокировав его, пока вы не закончите. Очевидно, что если вы сохраните этот проект в масштабе, у вас закончатся потоки пула потоков.
SleepAsyncB работает по таймеру. System.Threading.Timer отправляет обратный вызов в потоке пула потоков, а не создает каждый раз новый поток. В этом случае он просто мгновенно устанавливает результат на TaskCompletionSource.
The
TaskCompletionSource<TResult>type serves two related purposes, it is a source for creating a task, and the source for that task’s completion. ATaskCompletionSource<TResult>acts as the producer for aTask<TResult>and its completion. Unlike Tasks created byTask.Runand alike, theTaskhanded out byTaskCompletionSource<TResult>does not have any scheduled delegate associated with it, however provides methods that allow you to control the lifetime and completion of the associated Task.
По сути, вы берете шаблон событий, созданный Timer, и используете TaskCompletionSouce, чтобы заставить его действовать как Task. Ни один поток не блокируется таймаутом, и поэтому он более масштабируемый.
3) How can I call the two methods in main to make their purpose more obvious (and better high light their differences)?
Данный
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) I know async Task methods can be called with await, what about Tasks that lack async like these methods?
Конечно! и это общий шаблон, позволяющий избежать лишнего конечного автомата и обеспечить вам эффективность. Однако каждый раз, когда вы вызываете 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);
}
Масштабируемость, простота, без суеты.
Я полагаю, это для C#?