Что касается использования Task.Start (), Task.Run () и Task.Factory.StartNew ()

145

Я только что видел 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()?

Пожалуйста, помогите мне понять их реальное использование в соответствии со сценарием подробно с примерами, спасибо.

Mou
источник
есть старая статья, объясняющая, что здесь и здесь для новичковTask.Run - может быть, это ответит на ваш вопрос;)
Carsten
Вот пример того, где Task.Startэто действительно полезно.
Носератио
Возможный дубликат: В чем разница между Task.Run () и Task.Factory.StartNew ()
Майкл Фрейдгейм

Ответы:

175

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 Is Useless For Task.Run With async-await ). Подробнее Task.Factory.StartNewв Task.Run vs Task.Factory.StartNew

Никогда не создавайте Taskи не звоните, Start()если не найдете для этого очень вескую причину. Его следует использовать только в том случае, если у вас есть часть, которая должна создавать задачи, но не планировать их, а другая часть составляет расписание без создания. Это почти никогда не подходящее решение и может быть опасным. Подробнее в «Task.Factory.StartNew» vs «new Task (...). Start»

В заключение, в основном используйте Task.Run, используйте, Task.Factory.StartNewесли нужно, и никогда не используйте Start.

i3arnon
источник
5
u сказал: «Никогда не создавайте Task и не вызывайте 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
3

Краткий ответ :

Если вы не используете вложенные дочерние задачи и всегда хотите, чтобы ваши задачи выполнялись в пуле потоков , лучше использовать Task.Run.

Длинный ответ:

Task.Runи Task.Factory.StartNewоба обеспечивают поддержку для создания и планирования объектов Task, поэтому нам не нужно создавать 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что означает, что тот, который выполняет задачи в пуле потоков, всегда будет использоваться для выполнения задач.

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

Али Баят
источник