Pregunta

En particular, estoy buscando en el uso de TPL a comenzar (y esperar) procesos externos. Se ve el TPL a carga total de la máquina (tanto la CPU y E / S) antes de decidirse a iniciar otra tarea (de ahí - en mi caso - otro proceso externo)?

Por ejemplo:

Me quedan unos 100 archivos multimedia que necesitan ser codificada o transcodificado (por ejemplo, de WAV a FLAC o de FLAC a MP3). La codificación se realiza mediante el lanzamiento de un proceso externo (por ejemplo flac.exe o lame.exe). Cada archivo toma alrededor de 30 segundos. Cada proceso es principalmente vinculado a la CPU, pero hay un poco de I / O en allí. Tengo 4 núcleos, por lo que el peor de los casos (transcodificación canalizando el decodificador en el codificador) todavía sólo utiliza 2 núcleos. Me gustaría hacer algo como:

Parallel.ForEach(sourceFiles,
    sourceFile =>
        TranscodeUsingPipedExternalProcesses(sourceFile));

Será este puntapié inicial 100 tareas (y por tanto de 200 procesos externos que compiten por la CPU)? O va a ver que de la CPU ocupada y sólo hacer 2-3 a la vez?

¿Fue útil?

Solución

Usted va a ejecutar en un par de problemas aquí. El mecanismo para evitar la inanición del programador verá sus tareas como bloqueado, ya que esperar en los procesos. Le resultará difícil distinguir entre un hilo en un punto muerto y uno simplemente espera de un proceso de completa. Como resultado se puede programar nuevas tareas si sus tareas se ejecutan o un largo tiempo (véase más adelante). La heurística hillclimbing debería tener en cuenta la carga total en el sistema, tanto desde la aplicación y otros. Simplemente se trata de maximizar el trabajo hecho, por lo que añadirá más trabajo hasta que el rendimiento global del sistema deja de aumentar y luego se marcha atrás. No me que Esto afectará su aplicación pero el tema de evitación stavation probablemente lo hará.

Puede encontrar más detalles en cuanto a cómo funciona todo esto en Programación Paralela con Microsoft®.NET , Colin Campbell, Ralph Johnson, Ade Miller, Stephen Toub (un proyecto anterior es línea ) .

"El grupo de subprocesos .NET gestiona automáticamente el número de trabajadores subprocesos en el grupo. Se añade y elimina las discusiones de acuerdo a una función de heurística. El grupo de subprocesos .NET tiene dos mecanismos principales para inyectar hilos: un mecanismo de inanición-evitación que añade trabajador hilos si no ve progresos realizados en elementos en cola y un hillclimbing heurístico que trata de maximizar el rendimiento mientras se utiliza como pocos hilos como sea posible.

El objetivo de evitar la inanición es para evitar un punto muerto. Este tipo de interbloqueo puede ocurrir cuando un hilo espera trabajador para una sincronización evento que sólo puede ser satisfecha por un elemento de trabajo que aún está pendiente en las colas globales o locales del grupo de subprocesos. Si hubiera un fijo número de subprocesos de trabajo, y todos esos hilos fueron igualmente bloqueado, el sistema no podría nunca hacer más progresos. Adición de un nuevo subproceso de trabajo resuelve el problema.

Uno de los objetivos de la heurística de escalada es mejorar la utilización de núcleos cuando los hilos se bloquean por E / S o de otras condiciones de espera que detener el procesador. Por defecto, el grupo de subprocesos administrado tiene una subproceso de trabajo por núcleo. Si uno de estos subprocesos de trabajo se convierte bloqueado, hay una posibilidad de que un núcleo podría estar infrautilizado, dependiendo el volumen total de trabajo del equipo. La lógica de inyección hilo no distingue entre un hilo que está bloqueada y un hilo eso es la realización de una operación larga, uso intensivo del procesador. Por lo tanto, siempre que las colas globales o locales de la agrupación de hebras contienen pendientes elementos de trabajo, elementos de trabajo activas que toman mucho tiempo para correr (más de un segundo medio) puede desencadenar la creación de nuevo trabajador grupo de subprocesos hilos.

El grupo de subprocesos de .NET tiene una oportunidad para inyectar hilos de cada la ultima vez que un elemento de trabajo o en 500 milisegundos, lo que sea intervalos es más corto. El grupo de subprocesos utiliza esta oportunidad para intentar añadir hilos (O tomarlos de distancia), guiada por la retroalimentación de los cambios anteriores en el número de subprocesos. Si la adición de las discusiones parece estar ayudando rendimiento, el grupo de subprocesos añade más; de otro modo, se reduce el número de subprocesos de trabajo. Esta técnica se llama la heurística de escalada. Por lo tanto, una de las razones para mantener las tareas individuales a corto es evitar “La detección de hambre”, pero otra razón para mantenerlas cortas es dar a la agrupación de hebras más oportunidades para mejorar el rendimiento al el ajuste de la densidad de hilos. Cuanto más corta sea la duración de la persona tareas, más a menudo el grupo de subprocesos pueden medir el rendimiento y ajustar el número de hilos en consecuencia.

Para hacer este concreto, considere un ejemplo extremo. Suponer que tiene una simulación financiera compleja con 500 procesador de uso intensivo operaciones, cada uno de los cuales toma diez minutos en promedio completar. Si crea tareas de alto nivel en la cola global para cada de estas operaciones, se encuentra que after aproximadamente cinco minutos, el grupo de subprocesos crecerá a 500 subprocesos de trabajo. La razón es que el grupo de subprocesos ve todas las tareas como bloqueado y comienza a añadir nueva hilos a razón de aproximadamente dos hilos por segundo.

Lo malo de subprocesos de trabajo con 500? En principio, nada, si usted tiene 500 núcleos para que utilicen y enormes cantidades de sistema memoria. De hecho, esta es la visión de largo plazo de la computación paralela. Sin embargo, si usted no tiene esa cantidad de núcleos en su ordenador, se en una situación en la que muchos hilos están compitiendo por intervalos de tiempo. Esta situación se conoce como sobresuscripción procesador. permitiendo que muchos hilos de uso intensivo del procesador que compiten por el tiempo en el agrega un solo núcleo overhead cambio de contexto que puede reducir gravemente sistema global el rendimiento. Incluso si usted no se quede sin memoria, el rendimiento en este situación puede ser mucho, mucho peor que en el cálculo secuencial. (Cada cambio de contexto toma entre 6.000 y 8.000 ciclos de procesador.) El coste de la conmutación de contexto no es la única fuente de gastos generales. Un hilo administrado en .NET consume más o menos un megabyte de pila espacio, ya sea o no que el espacio se utiliza actualmente para la ejecución de funciones. Se tarda unos 200.000 ciclos de CPU para crear un nuevo hilo, y alrededor de 100.000 ciclos para retirar un hilo. Estas son operaciones costosas.

Mientras sus tareas no tener minutos cada uno, de la agrupación de hebras algoritmo de escalada con el tiempo se dará cuenta de que tiene demasiados hilos y la parte posterior corte en su propio acuerdo. Sin embargo, si usted tiene tareas que ocupar un subproceso de trabajo durante muchos segundos o minutos u horas, que se lanzan fuera de la heurística de la agrupación de hebras, y en ese momento se debe considerar una alternativa.

La primera opción es descomponer la aplicación en corto tareas que lo suficientemente rápido completa para la agrupación de hebras de éxito controlar el número de hilos para una óptima rendimiento. Una segunda posibilidad es implementar su propio programador de tareas objeto que no realiza la inyección hilo. Si sus tareas son de larga duración, que no necesita un programador de tareas altamente optimizado, porque el costo de la programación será insignificante en comparación con la ejecución el tiempo de la tarea. programa de desarrolladores de MSDN tiene un ejemplo de una aplicación de programación de tareas simple que limita el grado máximo de concurrencia. Para obtener más información, consulte la sección “Lectura adicional” al final de este capítulo.

Como último recurso, puede utilizar el método de SetMaxThreads configurar la clase ThreadPool con un límite superior para el número de subprocesos de trabajo, por lo general igual al número de núcleos (este es el Environment.ProcessorCount propiedad). Este límite superior se aplica para todo el proceso, incluyendo todos los dominios de aplicación. "

Otros consejos

La respuesta corta es:. No

Internamente, el TPL utiliza el estándar ThreadPool para programar sus tareas. Así que en realidad estás preguntando si la carga de la máquina ThreadPool toma en cuenta y no lo hace. La única cosa que limita el número de tareas que se ejecutan al mismo tiempo es el número de hilos en el grupo de subprocesos, nada más.

¿Es posible tener los procesos externos informan de nuevo a su aplicación una vez que estén listos? En ese caso, usted no tiene que esperar a que ellos (manteniendo las discusiones ocupadas).

realizó una prueba usando TPL / ThreadPool para programar un gran número de tareas que realizan giros en bucle. Usando una aplicación externa He cargado uno de los núcleos a 100% utilizando afinidad proc. El número de tareas activas que nunca disminuyó.

Aún mejor, me encontré con varias instancias de la misma CPU .NET TPL habilitado aplicación. El número de hilos para todas las aplicaciones era el mismo, y nunca fue inferior al número de núcleos, a pesar de que mi máquina era apenas utilizable.

Así, aparte teoría, TPL utiliza el número de núcleos disponibles, pero nunca El control de la carga real. Una muy mala aplicación en mi opinión.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top