Debo usar ThreadPools o la Biblioteca Paralela de tareas para operaciones vinculadas a IO


En uno de mis proyectos que es un poco un agregador, analizo feeds, podcasts y así de la web.

Si utilizo el enfoque secuencial, dado que un gran número de recursos, se necesita bastante tiempo para procesar todos ellos (debido a problemas de red y cosas similares);

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

Así que quiero implementar concurrencia y no pude decidir si debería usar básicamente ThreadPools para procesar con worker threads o simplemente confiar en TPL para ordenarlo.

ThreadPools seguro que lo hará maneje el trabajo por mí con hilos de trabajo y obtendré lo que espero (y en entornos de CPU multinúcleo, los otros núcleos también se utilizarán).

concurrencia

Pero todavía quiero considerar TPL también, ya que es el método de recomendación, 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 donde un entorno de un solo núcleo está presente. Si no me equivoco TPL comienza con un número worker-threads igual al número de núcleos CPU disponibles al principio. Temo que el TPL produzca resultados similares al enfoque secuencial para mi caso vinculado a IO.

Entonces, para las operaciones vinculadas a IO (en mi caso leyendo recursos de la web), ¿es mejor usar ThreadPools y controlar las cosas, o mejor simplemente confiar en TPL? ¿Se puede utilizar TPL también en escenarios vinculados a IO?

Actualización : Mi principal preocupación es que TP en un entorno de CPU de un solo núcleo TPL se comportará como ¿enfoque secuencial o seguirá ofreciendo concurrencia? Ya estoy leyendo Programación Paralela con Microsoft.NET y así el libro pero no pude encontrar una respuesta exacta para esto.

Nota: esta es una reformulación de mi pregunta anterior [ ¿Es posible usar la concurrencia de subprocesos y el paralelismo juntos?] que estaba bastante mal expresado.

Author: Community, 2011-03-07

6 answers

Así que decidí escribir pruebas para esto y verlo en datos prácticos.

Leyenda de ensayo

  • Itr: Iteración
  • Seq: Enfoque secuencial.
  • PrlEx: Extensiones paralelas - Paralelas.ForEach
  • TPL: Biblioteca paralela de tareas
  • TPool: ThreadPool

Resultados de las pruebas

CPU de un solo núcleo [Win7-32 ] runs se ejecuta bajo 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 ] runs se 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
________________________________________________________________________________

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] Supported 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 un solo núcleo o en uno de varios núcleos, Parallel Extensions, TPL y ThreadPool se comportan de la misma manera y dan resultados aproximados.
  • Siendo TPL tiene ventajas, como fácil manejo de excepciones, cancelación y apoyo capacidad de devolver fácilmente los resultados de la tarea. Aunque Extensiones paralelas es también otra alternativa viable.

Ejecutar pruebas por su cuenta

Puede descargar la fuente aquí y ejecutar por su cuenta. Si puedes publicar los resultados, también los agregaré.

Actualización: Corregido el enlace fuente.

 100
Author: HuseyinUslu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-11 09:50:09

Si está tratando de maximizar el rendimiento de las tareas vinculadas a IO, absolutamente debe combine las API tradicionales del Modelo de Procesamiento Asíncrono (APM) con su trabajo basado en TPL. Las APIs APM son la única manera de desbloquear el subproceso de CPU mientras la devolución de llamada de IO asíncrona está pendiente. El TPL proporciona el método auxiliar TaskFactory::FromAsync para ayudar a combinar el código APM y TPL.

Echa un vistazo a esta sección del SDK. NET en MSDN titulado TPL y. NET tradicional Programación asíncrona para obtener más información sobre cómo combinar estos dos modelos de programación para lograr el nirvana asíncrono.

 15
Author: Drew Marsh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-08 01:28:41

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 profundizar. El TPL le permite crear tareas de larga duración que no son parte del grupo de subprocesos de TPL y podrían servir bien a su propósito. El libro publicado que es una lectura libre Programación paralela con Microsoft.NET le dará mucho más información sobre cómo se debe usar el TPL. Siempre tienes la opción de dar Paralelo.Para, Tareas explicit parámetros cuántos hilos se deben asignar. Además de esto, puede reemplazar el programador de TPL con el suyo propio si desea un control total.

 2
Author: Alois Kraus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-06 22:30:35

Puede asignar su propio programador de tareas a una tarea TPL. Sin embargo, el trabajo predeterminado robar es bastante inteligente.

 1
Author: ehnmark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-06 22:26:34

Temo que el TPL produzca resultados similares al enfoque secuencial para mi caso vinculado a IO.

Creo que lo hará. ¿Cuál es el cuello de botella? ¿Está analizando o descargando? Multithreading no le ayudará mucho con la descarga de la web.

Usaría la Biblioteca de tareas Paralelas para recortar, aplicar máscara o efectos para las imágenes descargadas, cortar alguna muestra de podcast, etc. Es más escalable.

Pero no será el orden de magnitud acelerar. Gasta tu recursos para implementar algunas características, pruebas.

PS. "Wow mi función se ejecuta en 0.7 s en lugar de 0.9";)

 0
Author: Lukasz Madon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-06 22:15:24

Si paraleliza sus llamadas a las URL, creo que mejorará su aplicación, incluso si solo tiene 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 multihilo 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.

Al confiar en la tarea GetAsync, el cliente http usa un networkstream (socket, cliente tcp o lo que sea) y lo señala para elevar un evento cuando se realiza BeginRead/EndRead. Por lo tanto, no hay hilos involucrados en este momento.

Después de que se llame a la finalización, tal vez se cree un nuevo subproceso, pero depende de TaskScheduler (utilizado en la llamada GetAsync/ContinueWith call) crear un nuevo subproceso, usar un subproceso existente o insertar la tarea para usar el subproceso de llamada.

Si el AnalyzeThisWords se bloquea durante demasiado tiempo, entonces comienza a obtener cuellos de botella a medida que la" devolución de llamada " en el ContinueWith se realiza desde un grupo de subprocesos trabajador.

 0
Author: Rafael Diego Nicoletti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-06 01:31:00