c# - with - ¿Hay algún caso en el que sea preferible utilizar un antiguo objeto Thread antiguo en lugar de uno de los constructos más nuevos?
thread net core (10)
Veo mucha gente en publicaciones de blogs y aquí en SO, ya sea evitando o desaconsejando el uso de la clase Thread
en versiones recientes de C # (y me refiero, por supuesto, a 4.0+, con la adición de Task
y amigos). Incluso antes, hubo debates sobre el hecho de que la funcionalidad ThreadPool
puede reemplazar la funcionalidad de un hilo antiguo simple en muchos casos.
Además, otros mecanismos especializados están haciendo que la clase Thread
menos atractiva, como Timer
s que reemplaza el feo combo Thread
+ Sleep
, mientras que para GUIs tenemos BackgroundWorker
, etc.
Aún así, el Thread
parece seguir siendo un concepto muy familiar para algunas personas (incluido yo mismo), personas que, cuando se enfrentan a una tarea que implica algún tipo de ejecución paralela, saltan directamente al uso de la buena vieja clase de Thread
. Me he estado preguntando últimamente si es el momento de modificar mis formas.
Entonces, mi pregunta es, ¿hay algún caso en el que sea necesario o útil utilizar un antiguo objeto Thread
antiguo en lugar de uno de los constructos anteriores?
La clase Thread
no está obsoleta, aún es útil en circunstancias especiales.
Donde trabajo, escribimos un "procesador de fondo" como parte de un sistema de gestión de contenido: un servicio de Windows que supervisa directorios, direcciones de correo electrónico y fuentes RSS, y cada vez que aparece algo nuevo ejecuta una tarea en él, generalmente para importar el datos.
Los intentos de utilizar el grupo de subprocesos para esto no funcionaron: trata de ejecutar demasiadas cosas al mismo tiempo y destruir los discos, por lo que implementamos nuestro propio sistema de sondeo y ejecución utilizando directamente la clase Thread
.
La clase Thread no se puede volver obsoleta porque obviamente es un detalle de implementación de todos los otros patrones que mencionas.
Pero esa no es realmente tu pregunta; tu pregunta es
¿Hay algún caso en el que sea necesario o útil usar un antiguo objeto Thread antiguo en lugar de uno de los constructos anteriores?
Por supuesto. En precisamente aquellos casos en que uno de los constructos de nivel superior no satisface sus necesidades.
Mi consejo es que si te encuentras en una situación en la que las herramientas de abstracción más altas no satisfacen tus necesidades, y deseas implementar una solución usando hilos, entonces debes identificar la abstracción que realmente necesitas , y luego implementar esa abstracción. usando hilos , y luego usa la abstracción .
Las nuevas opciones hacen que el uso directo y la administración de los hilos (costosos) sean menos frecuentes.
personas que, cuando se enfrentan a una tarea que implica algún tipo de ejecución paralela, saltan directamente al uso de la buena vieja clase Thread.
Que es una forma muy costosa y relativamente compleja de hacer cosas en paralelo.
Tenga en cuenta que el gasto es más importante: no puede usar un hilo completo para hacer un trabajo pequeño, sería contraproducente. El ThreadPool combate los costos, la clase Tarea las complejidades (excepciones, espera y cancelación).
Los hilos son un bloque de construcción básico para ciertas cosas (a saber, paralelismo y asincronía) y, por lo tanto, no se deben quitar. Sin embargo , para la mayoría de las personas y la mayoría de los casos de uso hay cosas más apropiadas para usar que mencionó, como agrupaciones de subprocesos (que proporcionan una forma agradable de manejar muchos trabajos pequeños en paralelo sin sobrecargar la máquina al generar 2000 hilos a la vez), BackgroundWorker
(que encapsula eventos útiles para una sola obra de corta duración).
Pero solo porque en muchos casos son más apropiados ya que protegen al programador de reinventar innecesariamente la rueda, de cometer errores estúpidos y cosas por el estilo, eso no significa que la clase Thread sea obsoleta. Todavía es utilizado por las abstracciones mencionadas anteriormente y aún lo necesitaría si necesita un control detallado de los hilos que no están cubiertos por las clases más especiales.
En una línea similar, .NET
no prohíbe el uso de matrices, a pesar de que List<T>
se adapta mejor a muchos casos donde las personas usan matrices. Simplemente porque aún puede querer construir cosas que no están cubiertas por la lib estándar.
No es definitivamente obsoleto.
El problema con las aplicaciones multiproceso es que son muy difíciles de acertar (a menudo es importante el comportamiento indeterminista, los insumos, los resultados y también el estado interno), por lo que un programador debe esforzarse tanto como sea posible por el marco o las herramientas. Resúmalo. Pero, el enemigo mortal de la abstracción es el rendimiento.
Entonces, mi pregunta es, ¿hay algún caso en el que sea necesario o útil utilizar un antiguo objeto Thread antiguo en lugar de uno de los constructos anteriores?
Iría con hilos y bloqueos solo si hubiera problemas serios de rendimiento y objetivos de alto rendimiento.
Para responder a la pregunta de " ¿hay algún caso en el que sea necesario o útil usar un objeto Thread antiguo simple? ", Diría que un Thread antiguo simple es útil (pero no necesario) cuando tienes un proceso de larga ejecución que ganaste. Nunca he interactuado con un hilo diferente.
Por ejemplo, si está escribiendo una aplicación que se suscribe para recibir mensajes de algún tipo de cola de mensajes y su aplicación va a hacer algo más que procesar esos mensajes, entonces sería útil usar un hilo porque el hilo será autónomo (es decir, no está esperando que se haga), y no es de corta duración. Usar la clase ThreadPool es más para poner en cola un montón de elementos de trabajo efímeros y permitir que la clase ThreadPool administre eficientemente cada uno de ellos, ya que hay un nuevo subproceso disponible. Las tareas se pueden usar donde se usaría Thread directamente, pero en el escenario anterior no creo que te comprarían mucho. Te ayudan a interactuar con el hilo más fácilmente (lo cual no es necesario en el escenario anterior) y ayudan a determinar cuántos subprocesos realmente deberían usarse para el conjunto de tareas dado en función de la cantidad de procesadores que tienes (que no es lo que usted quiere, por lo que le diría a la tarea que lo suyo es LongRunning, en cuyo caso en la implementación 4.0 actual simplemente crearía un subproceso no agrupado por separado).
Podría comparar la clase Thread con ADO.NET. No es la herramienta recomendada para realizar el trabajo, pero no está obsoleta. Otras herramientas se construyen encima para facilitar el trabajo.
No está mal usar la clase Thread sobre otras cosas, especialmente si esas cosas no proporcionan la funcionalidad que necesita.
Probablemente no sea la respuesta que esperabas, pero utilizo Thread todo el tiempo al codificar contra .NET Micro Framework. MF es bastante reducido y no incluye abstracciones de mayor nivel y la clase Thread es súper flexible cuando necesitas obtener el último rendimiento de una CPU de MHz bajo.
Siempre he usado la clase Thread cuando necesito contar y controlar los hilos que he creado. Me doy cuenta de que podría usar el hilo de trabajo para guardar todo mi excelente trabajo, pero nunca he encontrado una buena manera de hacer un seguimiento de la cantidad de trabajo que se está realizando actualmente o cuál es el estado.
En su lugar, creo una colección y coloco los hilos en ellos después de que los gire: lo último que hace un hilo es eliminarse de la colección. De esa forma, siempre puedo decir cuántos hilos se están ejecutando, y puedo usar la colección para preguntarle a cada uno qué está haciendo. Si hay un caso en el que necesito matarlos a todos, normalmente tendrías que establecer algún tipo de indicador de "Abortar" en tu aplicación, esperar a que cada hilo lo note por sí mismo y rescindirlo tú mismo - en mi caso, yo puede recorrer la colección y emitir un Thread.Abort a cada uno por turno.
En ese caso, no he encontrado una manera mejor de trabajar directamente con la clase Thread. Como Eric Lippert mencionó, los otros son solo abstracciones de nivel superior, y es apropiado trabajar con las clases de nivel más bajo cuando las implementaciones de alto nivel disponibles no satisfacen sus necesidades. Del mismo modo que a veces necesita hacer llamadas a la API Win32 cuando .NET no aborda sus necesidades exactas, siempre habrá casos en los que la clase Thread sea la mejor opción a pesar de los recientes "avances".
Task
e Thread
son abstracciones diferentes. Si desea modelar un hilo, la clase Thread
sigue siendo la opción más adecuada. Por ejemplo, si necesita interactuar con el hilo actual, no veo ningún tipo mejor para esto.
Sin embargo, como usted señala, .NET ha agregado varias abstracciones dedicadas que son preferibles sobre el Thread
en muchos casos.