Tengo método:
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");
}
Y quiero comenzar este método en una nueva Tarea. Puedo comenzar una nueva tarea como esta
var task = Task.Factory.StartNew(new Action(Method));
o esto
var task = Task.Run(new Action(Method));
Pero, ¿hay alguna diferencia entre Task.Run()y Task.Factory.StartNew(). Ambos están utilizando ThreadPool e inician Method () inmediatamente después de crear la instancia de la Tarea. ¿Cuándo deberíamos usar la primera variante y cuándo la segunda?
c#
multithreading
task-parallel-library
Sergiy Lichenko
fuente
fuente

StartNewlos usos predeterminados,TaskScheduler.Currentque pueden ser el grupo de subprocesos, pero también podrían ser el subproceso de la interfaz de usuario.Respuestas:
El segundo método,
Task.Runse ha introducido en una versión posterior del marco .NET (en .NET 4.5).Sin embargo, el primer método
Task.Factory.StartNewle brinda la oportunidad de definir muchas cosas útiles sobre el hilo que desea crear, mientrasTask.Runque no proporciona esto.Por ejemplo, supongamos que desea crear un hilo de tareas de larga ejecución. Si se va a utilizar un subproceso del conjunto de subprocesos para esta tarea, esto podría considerarse un abuso del conjunto de subprocesos.
Una cosa que podría hacer para evitar esto sería ejecutar la tarea en un hilo separado. Un subproceso recién creado que se dedicaría a esta tarea y se destruiría una vez que su tarea se hubiera completado. No puede lograr esto con el
Task.Run, mientras que puede hacerlo con elTask.Factory.StartNew, como a continuación:Como se afirma aquí :
fuente
that’s exactly equivalent tono se mantiene.tha's exactly equivalent tono contiene. Gracias por adelantado. Sería bueno explicarlo con comentarios sobre su código. Gracias :)TaskScheduler.Default. Por favor, eche un vistazo aquí referencesource.microsoft.com/#mscorlib/system/threading/Tasks/… .La gente ya mencionó que
Es equivalente a
Pero nadie mencionó eso
Es equivalente a:
Como puede ver, dos parámetros son diferentes para
Task.RunyTask.Factory.StartNew:TaskCreationOptions-Task.RunusosTaskCreationOptions.DenyChildAttachque significa que las tareas secundarias no se pueden adjuntar a los padres, considere esto:Cuando invocamos
parentTask.Wait(),childTaskno se esperará, a pesar de que lo especificamosTaskCreationOptions.AttachedToParent, esto se debe a queTaskCreationOptions.DenyChildAttachprohíbe que los niños se unan a él. Si ejecuta el mismo código con enTask.Factory.StartNewlugar deTask.Run,parentTask.Wait()esperaráchildTaskporqueTask.Factory.StartNewusaTaskCreationOptions.NoneTaskScheduler-Task.Runutiliza, loTaskScheduler.Defaultque significa que el programador de tareas predeterminado (el que ejecuta tareas en Thread Pool) siempre se utilizará para ejecutar tareas.Task.Factory.StartNewpor otro lado utiliza loTaskScheduler.Currentque significa planificador del hilo actual, puede serTaskScheduler.Defaultpero no siempre. De hecho, cuando se desarrollan aplicacionesWinformsoWPFse requiere actualizar la interfaz de usuario desde el hilo actual, para que esta gente use elTaskScheduler.FromCurrentSynchronizationContext()programador de tareas, si crea involuntariamente otra tarea de ejecución larga dentro de la tarea que usó elTaskScheduler.FromCurrentSynchronizationContext()programador, la interfaz de usuario se congelará. Una explicación más detallada de esto se puede encontrar aquíPor lo tanto, en general, si no está utilizando la tarea secundaria anidada y siempre desea que sus tareas se ejecuten en Thread Pool, es mejor usarla
Task.Run, a menos que tenga algunos escenarios más complejos.fuente
Vea este artículo de blog que describe la diferencia. Básicamente haciendo:
Es lo mismo que hacer:
fuente
Se
Task.Runintrodujo en la versión más reciente de .NET Framework y se recomienda .El
Task.Factory.StartNewtiene más opciones, laTask.Runque es una abreviatura:Y por taquigrafía me refiero a un atajo técnico :
fuente
Según esta publicación de Stephen Cleary, Task.Factory.StartNew () es peligroso:
Aquí están las razones reales:
Eso significa que podría ejecutarse en el hilo de la interfaz de usuario si se completa una operación y se vuelve a ordenar al hilo de la interfaz de usuario debido a una continuación como Stephen Cleary explica más completamente en su publicación.
En mi caso, estaba tratando de ejecutar tareas en segundo plano al cargar una cuadrícula de datos para una vista mientras también mostraba una animación ocupada. La animación ocupada no se mostraba cuando se usaba,
Task.Factory.StartNew()pero la animación se mostraba correctamente cuando cambiaba aTask.Run().Para más detalles, consulte https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html
fuente
Además de las similitudes, es decir, Task.Run () es una abreviatura de Task.Factory.StartNew (), hay una pequeña diferencia entre su comportamiento en caso de delegados sincronizados y asíncronos.
Supongamos que hay dos métodos siguientes:
Ahora considere el siguiente código.
Aquí, sync1 y sync2 son del tipo Task <int>
Sin embargo, la diferencia viene en caso de métodos asíncronos.
En este escenario, async1 es del tipo Task <int>, sin embargo, async2 es del tipo Task <Task <int>>
fuente
Task.Runtiene incorporada la funcionalidad de desenvolvimiento delUnwrapmétodo. Aquí hay una publicación de blog que explica el razonamiento detrás de esta decisión.En mi aplicación que llama a dos servicios, comparé Task.Run y Task.Factory.StartNew . Descubrí que en mi caso ambos funcionan bien. Sin embargo, el segundo es más rápido.
fuente