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
StartNew
los usos predeterminados,TaskScheduler.Current
que 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.Run
se ha introducido en una versión posterior del marco .NET (en .NET 4.5).Sin embargo, el primer método
Task.Factory.StartNew
le brinda la oportunidad de definir muchas cosas útiles sobre el hilo que desea crear, mientrasTask.Run
que 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 to
no se mantiene.tha's exactly equivalent to
no 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.Run
yTask.Factory.StartNew
:TaskCreationOptions
-Task.Run
usosTaskCreationOptions.DenyChildAttach
que significa que las tareas secundarias no se pueden adjuntar a los padres, considere esto:Cuando invocamos
parentTask.Wait()
,childTask
no se esperará, a pesar de que lo especificamosTaskCreationOptions.AttachedToParent
, esto se debe a queTaskCreationOptions.DenyChildAttach
prohíbe que los niños se unan a él. Si ejecuta el mismo código con enTask.Factory.StartNew
lugar deTask.Run
,parentTask.Wait()
esperaráchildTask
porqueTask.Factory.StartNew
usaTaskCreationOptions.None
TaskScheduler
-Task.Run
utiliza, loTaskScheduler.Default
que significa que el programador de tareas predeterminado (el que ejecuta tareas en Thread Pool) siempre se utilizará para ejecutar tareas.Task.Factory.StartNew
por otro lado utiliza loTaskScheduler.Current
que significa planificador del hilo actual, puede serTaskScheduler.Default
pero no siempre. De hecho, cuando se desarrollan aplicacionesWinforms
oWPF
se 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.Run
introdujo en la versión más reciente de .NET Framework y se recomienda .El
Task.Factory.StartNew
tiene más opciones, laTask.Run
que 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.Run
tiene incorporada la funcionalidad de desenvolvimiento delUnwrap
mé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