c# - startnew - ¿Debo usar ThreadPools o Task Parallel Library para operaciones vinculadas a IO?
threadpool c# ejemplo (6)
Temo que TPL produzca resultados similares al enfoque secuencial para mi caso vinculado a IO.
Creo que lo hará. ¿Cuál es el cuello de botella? ¿Se está analizando o descargando? Multithreading no te ayudará mucho con la descarga desde la web.
Usaría la Biblioteca de tareas paralelas para recortar, aplicar máscaras o efectos para las imágenes descargadas, recortar algunas muestras de podcasts, etc. Es más escalable.
Pero no será el orden de magnitud acelerar. Dedique sus recursos a la implementación de algunas características, pruebas.
PD. "Vaya, mi función se ejecuta en 0.7 s en vez de 0.9";)
En uno de mis proyectos, que es un agregador, analizo feeds, podcasts y, por lo tanto, desde la web.
Si uso un enfoque secuencial, dado que hay una gran cantidad de recursos, lleva bastante tiempo procesarlos a todos (debido a problemas de red y cosas similares);
foreach(feed in feeds)
{
read_from_web(feed)
parse(feed)
}
Por lo tanto, quiero implementar la simultaneidad y no puedo decidir si básicamente debo usar ThreadPools para procesar con subprocesos de trabajo o simplemente confiar en TPL para ordenarlo.
ThreadPools seguro me encargará el trabajo con subprocesos de trabajo y obtendré lo que espero (y en los entornos de CPU multinúcleo, los otros núcleos también se utilizarán también).
Pero aún quiero considerar TPL también, ya que es un método recomendado, pero estoy un poco preocupado por ello. En primer lugar, sé que TPL utiliza ThreadPools, pero agrega una capa adicional de toma de decisiones. Me preocupa sobre todo la condición de que esté presente un entorno de núcleo único. Si no me equivoco, TPL comienza con un número de hilos de trabajo igual al número de núcleos de CPU disponibles desde el principio. Temo que TPL produzca resultados similares al enfoque secuencial para mi caso vinculado a IO.
Entonces, para las operaciones vinculadas a IO (en mi caso, leer recursos de la web), ¿es mejor usar ThreadPools y controlar las cosas, o mejor simplemente confiar en TPL? ¿Se puede utilizar TPL en escenarios vinculados a IO?
Actualización : Mi principal preocupación es que, en un entorno de CPU de un solo núcleo , TPL simplemente se comporte como un enfoque secuencial o ¿seguirá ofreciendo simultaneidad? Ya estoy leyendo Parallel Programming con Microsoft .NET y el book pero no pude encontrar una respuesta exacta para esto.
Nota: esto es una reformulación de mi pregunta anterior [ ¿Es posible usar la concurrencia de hilos y el paralelismo juntos? ] que estaba bastante mal formulado.
Entonces decidí escribir pruebas para esto y verlo en datos prácticos.
Leyenda de prueba
- Itr: iteración
- Seq: enfoque secuencial.
- PrlEx: Extensiones Paralelas - Paralelo.ParaEach
- TPL: Tarea Biblioteca paralela
- TPool: ThreadPool
Resultados de la prueba
CPU de un solo núcleo [Win7-32]: se ejecuta en VMWare -
Test Environment: 1 physical cpus, 1 cores, 1 logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________
Itr. Seq. PrlEx TPL TPool
________________________________________________________________________________
#1 10.82s 04.05s 02.69s 02.60s
#2 07.48s 03.18s 03.17s 02.91s
#3 07.66s 03.21s 01.90s 01.68s
#4 07.43s 01.65s 01.70s 01.76s
#5 07.81s 02.20s 01.75s 01.71s
#6 07.67s 03.25s 01.97s 01.63s
#7 08.14s 01.77s 01.72s 02.66s
#8 08.04s 03.01s 02.03s 01.75s
#9 08.80s 01.71s 01.67s 01.75s
#10 10.19s 02.23s 01.62s 01.74s
________________________________________________________________________________
Avg. 08.40s 02.63s 02.02s 02.02s
________________________________________________________________________________
CPU de un solo núcleo [WinXP]: se ejecuta en VMWare -
Test Environment: 1 physical cpus, NotSupported cores, NotSupported logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________
Itr. Seq. PrlEx TPL TPool
________________________________________________________________________________
#1 10.79s 04.05s 02.75s 02.13s
#2 07.53s 02.84s 02.08s 02.07s
#3 07.79s 03.74s 02.04s 02.07s
#4 08.28s 02.88s 02.73s 03.43s
#5 07.55s 02.59s 03.99s 03.19s
#6 07.50s 02.90s 02.83s 02.29s
#7 07.80s 04.32s 02.78s 02.67s
#8 07.65s 03.10s 02.07s 02.53s
#9 10.70s 02.61s 02.04s 02.10s
#10 08.98s 02.88s 02.09s 02.16s
________________________________________________________________________________
Avg. 08.46s 03.19s 02.54s 02.46s
________________________________________________________________________________
CPU de doble núcleo [Win7-64]
Test Environment: 1 physical cpus, 2 cores, 2 logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________
Itr. Seq. PrlEx TPL TPool
________________________________________________________________________________
#1 07.09s 02.28s 02.64s 01.79s
#2 06.04s 02.53s 01.96s 01.94s
#3 05.84s 02.18s 02.08s 02.34s
#4 06.00s 01.43s 01.69s 01.43s
#5 05.74s 01.61s 01.36s 01.49s
#6 05.92s 01.59s 01.73s 01.50s
#7 06.09s 01.44s 02.14s 02.37s
#8 06.37s 01.34s 01.46s 01.36s
#9 06.57s 01.30s 01.58s 01.67s
#10 06.06s 01.95s 02.88s 01.62s
________________________________________________________________________________
Avg. 06.17s 01.76s 01.95s 01.75s
________________________________________________________________________________
CPU de cuatro núcleos [Win7-64] - Compatible con HyprerThreading -
Test Environment: 1 physical cpus, 4 cores, 8 logical cpus.
Will be parsing a total of 10 feeds.
________________________________________________________________________________
Itr. Seq. PrlEx TPL TPool
________________________________________________________________________________
#1 10.56s 02.03s 01.71s 01.69s
#2 07.42s 01.63s 01.71s 01.69s
#3 11.66s 01.69s 01.73s 01.61s
#4 07.52s 01.77s 01.63s 01.65s
#5 07.69s 02.32s 01.67s 01.62s
#6 07.31s 01.64s 01.53s 02.17s
#7 07.44s 02.56s 02.35s 02.31s
#8 08.36s 01.93s 01.73s 01.66s
#9 07.92s 02.15s 01.72s 01.65s
#10 07.60s 02.14s 01.68s 01.68s
________________________________________________________________________________
Avg. 08.35s 01.99s 01.75s 01.77s
________________________________________________________________________________
Resumen
- Ya sea que se ejecute en un entorno de núcleo único o de núcleo múltiple, Parallel Extensions, TPL y ThreadPool se comporta de la misma manera y proporciona resultados aproximados .
- Aún así, TPL tiene ventajas como el fácil manejo de excepciones, el soporte de cancelación y la capacidad de devolver fácilmente los resultados de la Tarea . Aunque Parallel Extensions es también otra alternativa viable.
Ejecutando pruebas por su cuenta
Puede descargar la fuente here y ejecutarla por su cuenta. Si puede publicar los resultados, los agregaré también.
Actualización: se corrigió el enlace de origen.
Puede asignar su propio planificador de tareas a una tarea TPL. Sin embargo, el robo de trabajo predeterminado es bastante ingenioso.
Si intenta maximizar el rendimiento para las tareas vinculadas a IO, debe combinar absolutamente las API tradicionales del Modelo de procesamiento asíncrono (APM) con su trabajo basado en TPL. Las APM API son la única forma de desbloquear el hilo de la CPU mientras la devolución de llamada IO asíncrona está pendiente. El TPL proporciona el método auxiliar TaskFactory::FromAsync
para ayudar a combinar el código APM y TPL.
Consulte esta sección del .NET SDK en MSDN titulada TPL y la Programación asincrónica .NET tradicional para obtener más información sobre cómo combinar estos dos modelos de programación para lograr async nirvana.
Si paraleliza sus llamadas a las URL, creo que mejorará su aplicación, incluso si tiene solo un núcleo. Echa un vistazo a este código:
var client = new HttpClient();
var urls = new[]{"a", "url", "to", "find"};
// due to the EAP pattern, this will run in parallel.
var tasks = urls.Select(c=> client.GetAsync(c));
var result = Tasks.WhenAll(task).ContinueWith(a=> AnalyzeThisWords(a.Result));
result.Wait(); // don''t know if this is needed or it''s correct to call wait
La diferencia entre multiprocesamiento y asincronía en este caso es cómo se realiza la devolución de llamada / finalización.
Cuando se usa EAP, el número de tareas no está relacionado con el número de subprocesos.
Como está confiando en la tarea GetAsync, el cliente http usa un flujo de red (socket, tcp client o lo que sea) y lo señaliza para generar un evento cuando se realiza BeginRead / EndRead. Entonces, no hay hilos involucrados en este momento.
Después de invocar la finalización, tal vez se cree un nuevo subproceso, pero depende de TaskScheduler (usado en la llamada GetAsync / ContinueWith) para crear un nuevo subproceso, usar un subproceso existente o la tarea en línea para usar el subproceso de llamada.
Si AnalyzeThisWords
bloquea durante demasiado tiempo, entonces comienza a tener cuellos de botella cuando la "devolución de llamada" en el ContinueWith se realiza desde un trabajador del grupo de subprocesos.
Tiene razón en que el TPL elimina parte del control que tiene cuando crea su propio grupo de subprocesos. Pero esto solo es correcto si no quieres cavar más profundo. El TPL le permite crear Tareas de larga ejecución que no forman parte del conjunto de subprocesos de TPL y que podrían ser útiles para su propósito. El libro publicado que es una programación paralela de lectura libre con Microsoft .NET le dará mucha más información sobre cómo se debe usar el TPL. Siempre tiene la opción de dar a Paralle.For, los parámetros explícitos de la cantidad de subprocesos que se deben asignar. Además de esto, puede reemplazar el programador de TPL con el suyo propio si desea control total.