Что касается использования 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()?

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


есть старая статья, объясняющая, что здесь и здесь для новичковTask.Run - может быть, это ответит на ваш вопрос;)
Carsten

Вот пример того, где Task.Startэто действительно полезно.
Носератио

Ответы:


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.


5
u сказал: «Никогда не создавайте Task и не вызывайте Start ()» перенаправьте меня на любую хорошую запись, которая покажет, что может быть вызвана Task.Start (). Мне нужны подробности, потому что ты говоришь избегать этого. Спасибо за ответ.
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но не всегда.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.