В чем разница между Task.Run () и Task.Factory.StartNew ()

192

У меня есть метод:

private static void Method()
{
    Console.WriteLine("Method() started");

    for (var i = 0; i < 20; i++)
    {
        Console.WriteLine("Method() Counter = " + i);
        Thread.Sleep(500);
    }

    Console.WriteLine("Method() finished");
}

И я хочу запустить этот метод в новом задании. Я могу начать новую задачу, как это

var task = Task.Factory.StartNew(new Action(Method));

или это

var task = Task.Run(new Action(Method));

Но есть ли разница между Task.Run()и Task.Factory.StartNew(). Оба они используют ThreadPool и запускают метод () сразу после создания экземпляра задачи. Когда мы должны использовать первый вариант, а когда второй?

Сергей Личенко
источник
6
На самом деле, StartNew не должен использовать ThreadPool, см. Блог, на который я ссылаюсь, в моем ответе. Проблема заключается в использовании StartNewпо умолчанию, TaskScheduler.Currentкоторое может быть пулом потоков, но также может быть потоком пользовательского интерфейса.
Скотт Чемберлен
2
Возможный дубликат в отношении использования Task.Start (), Task.Run () и Task.Factory.StartNew ()
Ахмед Абдельхамид

Ответы:

198

Второй метод, Task.Runбыл представлен в более поздней версии .NET Framework (в .NET 4.5).

Тем не менее, первый метод Task.Factory.StartNewдает вам возможность определить множество полезных вещей о потоке, который вы хотите создать, но Task.Runне предоставляет этого.

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

Чтобы этого избежать, вы могли бы выполнить задачу в отдельном потоке. Недавно созданный поток , который будет посвящен этой задаче и будет уничтожен, как только ваша задача будет завершена. Вы не можете достичь этого с помощью Task.Run, в то время как вы можете сделать это с помощью Task.Factory.StartNew, как показано ниже:

Task.Factory.StartNew(..., TaskCreationOptions.LongRunning);

Как указано здесь :

Итак, в .NET Framework 4.5 Developer Preview мы представили новый метод Task.Run. Это ни в коем случае не устаревает Task.Factory.StartNew, а скорее должно рассматриваться как быстрый способ использовать Task.Factory.StartNew без необходимости указывать кучу параметров. Это ярлык. Фактически, Task.Run фактически реализован в рамках той же логики, что и Task.Factory.StartNew, просто передавая некоторые параметры по умолчанию. Когда вы передаете действие в Task.Run:

Task.Run(someAction);

это в точности эквивалентно:

Task.Factory.StartNew(someAction, 
    CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
Christos
источник
4
У меня есть кусок кода, где государственное управление that’s exactly equivalent toне держит.
Емаборса
7
@Emaborsa Я был бы признателен, если бы вы могли опубликовать этот кусок кода и уточнить свои аргументы. Заранее спасибо !
Христос
4
@Emaborsa Вы можете создать гист , gist.github.com и поделиться им. Однако, кроме как поделиться этой суть, пожалуйста, укажите, как вы достигли результата, который фраза tha's exactly equivalent toне имеет. Заранее спасибо. Было бы неплохо объяснить с комментариями к вашему коду. Спасибо :)
Христос
8
Также стоит отметить, что Task.Run по умолчанию разворачивает вложенную задачу. Я рекомендую прочитать эту статью об основных различиях: blogs.msdn.microsoft.com/pfxteam/2011/10/24/…
Павел Мага,
1
@ The0bserver Нет, это так TaskScheduler.Default. Пожалуйста, смотрите здесь referencesource.microsoft.com/#mscorlib/system/threading/Tasks/... .
Христос