Экземпляр класса Task (Task.Factory.StartNew или TaskCompletionSource)

#c# #multithreading #task-parallel-library

#c# #многопоточность #задача-параллельная-библиотека

Вопрос:

Вероятно, это довольно простой вопрос, но я просто хотел убедиться, что у меня все в порядке с головой. Сегодня я копался в библиотеке TPL и обнаружил, что существует два способа создания экземпляра класса Task.

Способ, которым я

  Task<int> t1 = Task.Factory.StartNew(() =>
                {
                    //Some code
                    return 100;

                });
  

Способ II

   TaskCompletionSource<int> task = new TaskCompletionSource<int>();
  Task t2 = task.Task;
  task.SetResult(100);
  

Теперь я просто хотел знать, что

  1. Есть ли какая-либо разница между этими экземплярами?
  2. Если да, то что?

Ответ №1:

Во втором примере не создается «реальная» задача, т.Е. нет делегата, который что-либо делает.

Вы используете его в основном для представления интерфейса задачи вызывающей стороне. Посмотрите на пример в msdn

     TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
    Task<int> t1 = tcs1.Task;

    // Start a background task that will complete tcs1.Task
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        tcs1.SetResult(15);
    });

    // The attempt to get the result of t1 blocks the current thread until the completion source gets signaled.
    // It should be a wait of ~1000 ms.
    Stopwatch sw = Stopwatch.StartNew();
    int result = t1.Resu<
    sw.Stop();

    Console.WriteLine("(ElapsedTime={0}): t1.Result={1} (expected 15) ", sw.ElapsedMilliseconds, result);
  

Комментарии:

1. Чтобы добавить немного больше деталей, TaskCompletionSource — это способ переноса асинхронных операций, которые в противном случае в настоящее время не поддерживаются такими вещами, как TaskFactory. Из синхронизации. Одним из примеров использования TaskCompletionSource является перенос основанных на событиях реализаций шаблона asynchronouns, таких как WebClient. Загрузка stringasync. Дополнительные примеры см. msdn.microsoft.com/en-us/magazine/ff959203.aspx

Ответ №2:

Поскольку вы не запускаете никаких асинхронных операций способом 1 выше, вы теряете время, используя другой поток из пула потоков (возможно, если вы не измените значение по умолчанию TaskScheduler ).

Однако способом 2 вы генерируете завершенную задачу и выполняете ее в том же потоке, в котором являетесь. TCS также можно рассматривать как задачу без потоков (возможно, неправильное описание, но используется несколькими разработчиками).

Комментарии:

1. @PeterRitchie ты читал, что я написал? Если вы собираетесь запускать код, который не нуждается в переключении потоков, но должен возвращать объект Task, вы ничего не делаете, кроме как теряете время, используя Task.Factory.StartNew . Прекратите его использование и используйте TCS уже.

2. @PeterRitchie и Task.Factory.StartNew это не волшебная палочка, и она не асинхронна! Вы можете назвать это многопоточным, но не асинхронным. Асинхронность и многопоточность различны.

3. StartNew задокументирован как «Делегат действия для асинхронного выполнения». Возможно, поток не используется для асинхронности, но он является асинхронным.

4. как ядро синхронизации может быть асинхронным? это невозможно.