creo que el TPL (TaskFactory.Startnew) funciona de forma similar a ThreadPool.QueueUserWorkItem porque i t colas de trabajo en un hilo en el grupo de subprocesos.
Pretty much.
De lo que he estado leyendo parece que async/await solo "a veces" crea un nuevo hilo.
En realidad, nunca lo hace. Si quieres multihilo, debes implementarlo tú mismo. Hay un nuevo método Task.Run
que es solo una abreviatura de Task.Factory.StartNew
, y es probablemente la forma más común de iniciar una tarea en el grupo de subprocesos.
Si estaba tratando con puertos de terminación de E/S, puedo ver que no es necesario crear un nuevo hilo, pero de lo contrario, creo que debería hacerlo.
Bingo. Entonces, los métodos como Stream.ReadAsync
realmente crearán un contenedor Task
alrededor de un IOCP (si el Stream
tiene un IOCP).
También puede crear algunas "tareas" que no sean de E/S ni de CPU. Un ejemplo simple es Task.Delay
, que devuelve una tarea que se completa después de un período de tiempo.
Lo bueno de async
/await
es que se puede programar de algo de trabajo para el grupo de subprocesos (por ejemplo, Task.Run
), hacer alguna operación de E/S determinada (por ejemplo, Stream.ReadAsync
), y hacer alguna otra operación (por ejemplo, Task.Delay
) ... ¡y todas son tareas! Se pueden esperar o usar en combinaciones como Task.WhenAll
.
Cualquier método que devuelva Task
puede ser await
ed - no tiene que ser un método async
. Entonces, Task.Delay
y las operaciones de E/S solo usan TaskCompletionSource
para crear y completar una tarea: lo único que se hace en el grupo de subprocesos es completar la tarea real cuando ocurre el evento (tiempo de espera, finalización de E/S, etc.).
Creo que mi comprensión de FromCurrentSynchronizationContext siempre fue un poco confusa también. Siempre pensé que era, en esencia, el hilo de UI.
Escribí an article en SynchronizationContext
. La mayoría de las veces, SynchronizationContext.Current
:
- es un contexto de IU si el hilo actual es un hilo de IU.
- es un contexto de solicitud ASP.NET si el hilo actual está dando servicio a una solicitud ASP.NET.
- es un contexto de grupo de subprocesos de lo contrario.
Cualquier hilo puede fijar sus propias SynchronizationContext
, por lo que hay excepciones a las reglas anteriores.
Tenga en cuenta que el valor predeterminado awaiter Task
programará el resto del método async
de la corriente SynchronizationContext
si no es nulo; de lo contrario, continúa en el número actual TaskScheduler
. Esto no es tan importante hoy, pero en el futuro cercano será una distinción importante.
Escribí mi propio async
/await
intro en mi blog, y Stephen Toub publicó recientemente un excelente async
/await
FAQ.
En relación con "concurrencia" vs "multiproceso", consulte this related SO question. Yo diría que async
habilita la simultaneidad, que puede ser multiproceso o no. Es fácil de usar await Task.WhenAll
o await Task.WhenAny
para realizar un procesamiento simultáneo, y a menos que use explícitamente el grupo de subprocesos (por ejemplo, Task.Run
o ConfigureAwait(false)
), puede tener varias operaciones simultáneas en progreso al mismo tiempo (por ejemplo, múltiples E/S u otras tipos como Delay
) - y no hay hilo necesario para ellos. Utilizo el término "simultaneidad de subproceso único" para este tipo de escenario, aunque en un host ASP.NET, en realidad se puede terminar con " -competencia en threads". Que es bastante dulce
En realidad, TaskCreationOptions.LongRunning no garantiza un "nuevo hilo". Por MSDN, * la opción "LongRunning" solo proporciona una pista para el planificador; no garantiza un hilo dedicado. * Lo descubrí por el camino difícil. – eduncan911
@ eduncan911 aunque lo que dices acerca de la documentación es correcto, busqué el código fuente de TPL hace un tiempo y estoy bastante seguro de que siempre se crea un nuevo subproceso dedicado cuando se especifica 'TaskCreationOptions.LongRunning'. –
@ZaidMasud: Es posible que desee echar otro vistazo.Sé que estaba agrupando los hilos porque 'Thread.CurrentThread.IsThreadPoolThread' volvía a ser verdadero para los hilos de corta duración de unos pocos cientos de milisegundos. sin mencionar las variables ThreadStatic que estaba usando sangrado en múltiples hilos, causando todo tipo de havok. Tuve que forzar mi código para actualizar múltiples Thread() s, la forma de la vieja escuela, para garantizar un hilo dedicado. En otras palabras, no podría usar TaskFactory para hilos dedicados. Opcionalmente, podría implementar su propio 'TaskScheduler' que siempre devuelve un hilo dedicado. – eduncan911