Що стосується використання Task.Start (), Task.Run () та Task.Factory.StartNew ()


143

Щойно я побачив 3 підпрограми щодо використання TPL, які виконують ту саму роботу; ось код:

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Create a task and supply a user delegate by using a lambda expression. 
    Task taskA = new Task( () => Console.WriteLine("Hello from taskA."));
    // Start the task.
    taskA.Start();

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                  Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Define and run the task.
    Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                      Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Better: Create and start the task in one operation. 
    Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                    Thread.CurrentThread.Name);

    taskA.Wait();                  
}

Я просто не розумію , чому MS дає 3 різних способи запуску завдань в TPL , оскільки всі вони працюють однаково: Task.Start(), Task.Run()і Task.Factory.StartNew().

Скажіть, чи є Task.Start(), Task.Run()і Task.Factory.StartNew()всі вони використовуються з однією метою або вони мають різне значення?

Коли слід використовувати одне Task.Start(), коли слід застосовувати Task.Run()і коли слід використовувати Task.Factory.StartNew()?

Будь ласка, допоможіть мені зрозуміти їх реальне використання відповідно до сценарію, докладно з прикладами, дякую.


є стара стаття, яка пояснює, що тут і тут для новішихTask.Run - можливо, це відповість на ваше запитання;)
Карстен

Ось приклад того, де Task.Startнасправді корисно.
нісраціо

Відповіді:


171

Task.Runце скорочення для Task.Factory.StartNewконкретних безпечних аргументів:

Task.Factory.StartNew(
    action, 
    CancellationToken.None, 
    TaskCreationOptions.DenyChildAttach, 
    TaskScheduler.Default);

Він був доданий у .Net 4.5, щоб допомогти з все частішим використанням asyncта розвантаженням роботи на ThreadPool.

Task.Factory.StartNew(додано разом із TPL у .Net 4.0) набагато надійніший. Використовувати його слід лише в тому випадку, коли Task.Runцього недостатньо, наприклад, коли ви хочете використовувати TaskCreationOptions.LongRunning(хоча це непотрібно, коли делегат асинхронізується. Більше про це в моєму блозі: LongRunning є марним для Task.Run With async-wait ). Детальніше про Task.Factory.StartNewв Task.Run проти Task.Factory.StartNew

Ніколи не створюйте Taskта дзвоніть, Start()якщо не знайдете надзвичайно вагомих причин для цього. Його слід використовувати лише у тому випадку, якщо у вас є частина, яка потребує створення завдань, але не планує їх, та інша частина, яка планує без створення. Це майже ніколи не є відповідним рішенням і може бути небезпечним. Детальніше в "Task.Factory.StartNew" vs "нове завдання (...). Старт"

На закінчення, в основному, використовуйте Task.Run, використовуйте, Task.Factory.StartNewякщо потрібно, і ніколи не використовуйте Start.


5
Ви сказали: "Ніколи не створюйте Завдання та не дзвоніть Start ()", перенаправляйте мене на будь-яке добре записування, яке покаже, що може викликати Task.Start (). Мені потрібні деталі, тому що ур говорить, щоб уникнути цього. дякую за відповідь
Mou

ru говорити про це посилання blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx ??
Mou

1
@Mou Task.Startв основному має місце для спадкування типів.
Юваль Іцчаков

1
@Mou Це неефективно, оскільки вимагає синхронізації, щоб переконатися, що його викликають лише один раз. Інших варіантів немає.
i3arnon

2
@Mou Ви, ймовірно, повинні прочитати публікацію, яка пояснює це питання blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx
i3arnon

2

Коротка відповідь :

Якщо ви не використовуєте вкладені дитячі завдання і завжди хочете, щоб ваші завдання виконувались у Thread Pool , краще використовувати Task.Run.

Довга відповідь:

Task.Runі Task.Factory.StartNewобидва надають підтримку для створення та планування об’єктів Завдання, тому нам не потрібно створювати Taskта дзвінкиStart()

Task.Run(action);

Еквівалентний:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

І

Task.Factory.StartNew(action);

Еквівалентний:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

Task.Runвикористовує, TaskCreationOptions.DenyChildAttachщо означає, що дитячі завдання не можуть бути прикріплені до батьків, і він використовує, TaskScheduler.Defaultщо означає, що те, що виконує завдання в пулі Thread, завжди буде використовуватися для виконання завдань.

Task.Factory.StartNewвикористовує, TaskScheduler.Currentщо означає планувальник поточного потоку, це може бути, TaskScheduler.Defaultале не завжди.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.