70

En uno de mis proyectos que es algo así como un agregador, analizo feeds, podcasts y demás desde la web.Debo usar ThreadPools o Task Parallel Library para operaciones IO-bound

Si uso un enfoque secuencial, dado que hay una gran cantidad de recursos, lleva bastante tiempo procesarlos todos (debido a problemas de red y cosas similares);

foreach(feed in feeds) 
{ 
    read_from_web(feed) 
    parse(feed) 
} 

Así que desea implementar la concurrencia y no podía decidir si debería utilizar básicamente ThreadPools para procesar con subprocesos de trabajo o simplemente confiar en TPL para conseguir resolver el problema.

ThreadPools seguro me encargará el trabajo con hilos de trabajo y obtendré lo que espero (y en entornos de CPU multi-core, los otros núcleos también se utilizarán también).

concurrency

pero todavía quiero considerar TPL también, ya que es recomienda método, pero estoy un poco preocupado por él. 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 utilizar 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 un solo núcleo de la CPU se TPL simplemente comportarse como enfoque secuencial o va a seguir ofreciendo la concurrencia? Ya estoy leyendo Parallel Programming with Microsoft .NET y el book pero no pude encontrar una respuesta exacta para esto.

Nota: esto es una nueva redacción de mi pregunta anterior [Is it possible to use thread-concurrency and parallelism together?] que fue bastante fraseada mal.

Respuesta

100

Por lo tanto, decidí escribir pruebas para esto y verlo en datos prácticos.

prueba Leyenda

  • Itr: La iteración
  • Sec: enfoque secuencial.
  • PrlEx: Parallel Extensiones - Parallel.ForEach
  • TPL: Tarea Parallel Library
  • TPool: ThreadPool

Resultados de la Prueba

Single-Core CPU [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 
________________________________________________________________________________ 

solo núcleo de CPU [WinXP] - ejecuta bajo 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 
________________________________________________________________________________ 

Dual-Core CPU [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 
________________________________________________________________________________ 

Quad-Core CPU [Win7 -64] - HyprerThreading Soportado -

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 
________________________________________________________________________________ 

Sumarización

  • Ya sea que ejecute en un entorno de un solo núcleo o un multi-núcleo de uno, extensiones paralelas, TPL y ThreadPool comporta de la misma y da resultados aproximados.
  • Aún TPL tiene ventajas como un fácil manejo excepción, el apoyo cancelación y capacidad de volver fácilmente resultados de la tarea. Aunque Parallel Extensions es también otra alternativa viable.

pruebas se ejecutan en su propia

Puede descargar el código fuente here y ejecutar en-su-propio. Si puede publicar los resultados, los agregaré también.

Actualización: se corrigió el enlace de origen.

+6

+1 Para resolver su problema utilizando un enfoque científico. Si no me equivoco, todas las tecnologías anteriores usan el grupo de subprocesos, lo que explica los resultados similares. En general, me gusta usar las extensiones paralelas porque la sintaxis es muy simple y soy vago. –

+0

He fomentado la limpieza de las fuentes; https://github.com/raistlinthewiz/concurrency-tests – HuseyinUslu

+1

Gracias por revisar todo el trabajo para hacer la prueba. – GregoryBrad

0

Me 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áscara o efectos para las imágenes descargadas, recortar algunas muestras del podcast, etc. Es más escalable.

Pero no será el orden de magnitud de la velocidad. Dedique sus recursos a la implementación de algunas características, pruebas.

PS. "Vaya, mi función se ejecuta en 0.7 s en vez de 0.9";)

+0

El cuello de botella es la descarga del contenido. Un usuario habitual suscribe más de 10 feeds y, a partir de mis pruebas, lleva más de 15 segundos, al menos para mi subconjunto de prueba, descargarlos y analizarlos con un enfoque secuencial. Siento que hay suficiente espacio para mejorar. – HuseyinUslu

+0

Según los resultados de las pruebas que publiqué, parece que era cierto que había suficiente margen de mejora. – HuseyinUslu

1

Puede asignar su propio task scheduler a una tarea TPL. El predeterminado work stealing es bastante ingenioso.

+0

He leído ese recurso y realmente estoy preocupado por esto; En .NET Framework 4, el planificador de tareas predeterminado está estrechamente integrado con el grupo de subprocesos. Si usa el programador de tareas predeterminado, los hilos de trabajo que ejecutan tareas paralelas son administrados por la clase .NET ThreadPool. ** Generalmente, hay al menos tantos hilos de trabajo como núcleos ** en su computadora. - ¿Qué sucede si me estoy ejecutando en un entorno de núcleo único? No puedo encontrar ninguna aclaración al respecto .. – HuseyinUslu

+1

Por lo tanto, desea aplicar un _minimum_ grado de paralelismo, p. Ej. al final X grados, en este caso? 'TaskCreationOptions.LongRunning' [might] (http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/8304b44f-0480-488c-93a4-ec419327183b/) sea lo que quiera. Un planificador personalizado es otra opción si no puede convencer al predeterminado para que haga lo que desea. – ehnmark

+0

En realidad parece basarse en los resultados de las pruebas que publiqué, mis preocupaciones no eran válidas. – HuseyinUslu

2

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 lectura gratuita Parallel Programming with Microsoft .NET le dará mucha más información sobre cómo se debe usar el TPL. Usted siempre tiene la opción de dar a Paralle.For, Tasks explicit parámetros cuántos hilos se deben asignar. Además de esto, puede reemplazar el planificador TPL con el suyo propio si desea control total.

15

Si usted está tratando de maximizar el rendimiento para las tareas con destino a IO es absolutamente debe combinar las API tradicionales asíncrono Modelo de procesamiento (APM) con su trabajo basado 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 the TaskFactory::FromAsync helper method para ayudar a combinar el código APM y TPL.

Consulte esta sección del .NET SDK en MSDN titulada TPL and Traditional .NET Asynchronous Programming para obtener más información sobre cómo combinar estos dos modelos de programación para lograr async nirvana.

0

Si paraleliza sus llamadas a las URL, creo que mejorará su aplicación, incluso si tiene solo un núcleo. Tome una mirada en 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 multihilo y asincronía en este caso es cómo se realiza la devolución de llamada/finalización.

Al usar 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 utiliza 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 ejecutar la finalización, tal vez se crea un nuevo hilo, pero depende de TaskScheduler (utilizado en llamadas GetAsync/ContinueWith) para crear un nuevo hilo, usar un hilo existente o en línea la tarea para usar el hilo que llama .

Si el AnalyzeThisWords bloquea 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.

Cuestiones relacionadas