Асинхронные методы, использующие или не использующие пул потоков, масштабируемые или нет

не могли бы вы помочь мне понять разницу между двумя методами здесь:

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#?

Kenneth K. 19.10.2018 22:46

да, Кеннет, это для C#

Sami 19.10.2018 22:49

Этот вопрос ведет в кроличью нору

TheGeneral 20.10.2018 01:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
112
1

Ответы 1

На этот вопрос сложно ответить, потому что он сравнивает яблоки с апельсинами, утверждает, что это фрукты, и пытается сравнить их друг с другом.

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. A TaskCompletionSource<TResult> acts as the producer for a Task<TResult>and its completion. Unlike Tasks created by Task.Run and alike, the Task handed out by TaskCompletionSource<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); 
}

Масштабируемость, простота, без суеты.

Другие вопросы по теме