Нарезка резьбы.StartNew() и.Подождите()


Я даже не претендую на понимание потоковой обработки в C#, поэтому я ищу действительно простое объяснение потокам - более конкретно функцию StartNew() в .NET 4.

Я использую следующее, чтобы вызвать другой метод с своего рода подходом "пожар и забвение". Я мог бы сделать это, когда веб-странице нужно инициировать трудоемкий процесс, но когда странице на самом деле не нужно ждать результата. Как я понимаю, метод DoSomething() будет выполняться "асинхронно."

System.Threading.Tasks.Task.Factory.StartNew(() =>
{
    DoSomething();
});
Вышеприведенный код, похоже, работает именно так, как я хочу, хотя у меня есть смутное подозрение, что я на самом деле не использую его по назначению. Я также был пойман с его помощью в консольных приложениях, которые закрываются до запуска метода DoSomething (). Я не уверен, почему он работает на веб-страницах, но не консольных приложениях - я предполагаю, потому что пул приложений продолжает работать, даже когда страница была выгружена.

Что меня действительно смущает, так это то, что у меня есть видел много примеров, где они заканчиваются таким кодом .Ждать(). Насколько я понимаю, свои .Wait() означает, что остальная часть кода на этой странице будет ждать, пока не будет запущен метод DoSomething ()... в каком случае - в моем ограниченном понимании - это, кажется, сводит на нет все преимущества использования StartNew() в первую очередь?

Я надеюсь, что кто-нибудь поможет мне объяснить это так, чтобы мой простой маленький ум понял! Возможно, вы также можете объяснить лучший способ вызова метода с помощью fire-and-forget подходить? Большое спасибо!
1 2

1 ответ:

System.Threading.Tasks.Task.Factory.StartNew(() =>
{
    DoSomething();
})

Это существенно разгрузит работу на ThreadPool. Поток ThreadPool используется, как только он доступен (это означает, что он может быть фактически выполнен в разное время, если пул потоков заполнен).

Вызывая .Wait() в конце, это будет блокировать, пока эта задача не завершит выполнение. По сути, он не позволит основному потоку работать, пока он не будет завершен, и может привести к проблемам с производительностью в зависимости от того, как долго DoSomething() выполняется.

Лучший подход заключается в том, чтобы используйте async/await, чтобы ваше приложение могло продолжать реагировать, не связывая основную Thread.

Также обратите внимание, что вы должны использовать Task.Run вместо StartNew. Если только вам не нужно предоставить другие параметры (например, маркер отмены, расписание и т. д.), Task.Run используется по умолчанию.

Например:

// fire and forget, this will run on a thread once one is available on the thread pool
Task.Run(()=>
{
    DoSomething();
});

// fire and wait until exeuction has finished. this will block all activity until it is done
Task.Run(()=>
{
    DoSomething();
}).Wait();

// fire and and wait until the task is completed but do not block the current thread.
private async void DoSomethingAsync()
{
    await Task.Run(()=>
    {
        DoSomething();
    });
    // perform work after
}

Примечание: Как отметил VMAtm, " запуск задачи в ASP.NET приложение может быть опасным, так как оно может быть приостановлено с потоком IIS сам ".

Почему это опасно?
  • необработанное исключение в потоке, не связанном с запросом, будет снимите этот процесс.
  • Если вы запускаете сайт в веб-ферме, вы можете получить несколько экземпляров вашего приложения, которые пытаются выполнить одну и ту же задачу одновременно.
  • домен приложений, в котором работает ваш сайт, может отключиться по ряду причин и снять фоновую задачу с ним.

Подробнее: http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx/

Как запускать задачи на ASP.NET приложение: http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx