¿Alguien puede sugerir escenarios típicos donde la clase Partitioner
introducida en .NET 4.0 puede/debe ser utilizada?Cuándo usar la clase Partitioner?
Respuesta
La clase Partitioner
se utiliza para hacer las ejecuciones paralelas más grueso. Si tiene muchas tareas pequeñas para ejecutar en paralelo, la sobrecarga de invocar a los delegados para cada una puede ser prohibitiva. Al usar Partitioner
, puede reorganizar la carga de trabajo en fragmentos y hacer que cada invocación paralela funcione en un conjunto ligeramente más grande. La clase abstrae esta característica y puede dividir en función de las condiciones reales del conjunto de datos y los núcleos disponibles.
Ejemplo: Imagine que desea ejecutar un cálculo simple como este en paralelo.
Parallel.ForEach(Input, (value, loopState, index) => { Result[index] = value*Math.PI; });
Eso invocaría al delegado para cada entrada en Entrada. Hacerlo agregaría un poco de sobrecarga a cada uno. Mediante el uso de Partitioner
podemos hacer algo como esto
Parallel.ForEach(Partitioner.Create(0, Input.Length), range => {
for (var index = range.Item1; index < range.Item2; index++) {
Result[index] = Input[index]*Math.PI;
}
});
Esto reducirá el número de invoca como cada invocación funcionará en un conjunto más amplio. En mi experiencia, esto puede aumentar significativamente el rendimiento al paralelizar operaciones muy simples.
Para poner en paralelo una operación en una fuente de datos, uno de los pasos esenciales es dividir la fuente en varias secciones a las que se puede acceder simultáneamente por varios hilos. PLINQ y la Biblioteca paralela de tareas (TPL) proporcionan particionadores predeterminados que funcionan de forma transparente cuando se escribe una consulta paralela o un bucle ForEach. Para escenarios más avanzados, puede conectar su propio particionador.
Leer más here:
que me gustaría añadir a eso: En términos generales * * que no lo usa. PLINQ lo hace, y probablemente se saldrá con la suya con los particionadores por defecto. –
La partición de rango, como sugiere Brian Rasmussen, es un tipo de partición que se debe usar cuando el trabajo requiere mucha CPU, tiende a ser pequeño (en relación con una llamada a método virtual), se deben procesar muchos elementos y mayormente constante cuando se trata de tiempo de ejecución por elemento.
El otro tipo de partición que se debe considerar es la partición de fragmentos. Este tipo de particionamiento también se conoce como un algoritmo de equilibrio de carga porque un subproceso de trabajo rara vez se quedará inactivo mientras haya más trabajo por hacer, que no es el caso para una partición de rango.
Se debe usar una partición de fragmento cuando el trabajo tiene algunos estados de espera, tiende a requerir más procesamiento por elemento o cada elemento puede tener tiempos de procesamiento de trabajo significativamente diferentes.
Un ejemplo de esto podría ser la lectura en la memoria y el procesamiento de 100 archivos con tamaños muy diferentes. Un archivo de 1K se procesará en mucho menos tiempo que un archivo de 1mb. Si se utiliza una partición de rango para esto, algunos subprocesos podrían permanecer inactivos durante un tiempo porque procesaron archivos más pequeños.
A diferencia de una partición de rango, no hay forma de especificar el número de elementos que cada tarea debe procesar, a menos que escriba su propio particionador personalizado. Otra desventaja de usar una partición de fragmento es que puede haber algo de contención cuando vuelve a obtener otro fragmento, ya que se usa un bloqueo exclusivo en ese punto. Por lo tanto, es evidente que una partición de fragmento no debe utilizarse para pequeñas cantidades de trabajo intensivo de CPU.
El particionador de fragmentos predeterminado comienza con un tamaño de fragmento de 1 elemento por fragmento. Después de que cada subproceso procesa tres trozos de 1 elemento, el tamaño del trozo se incrementa a 2 elementos por porción.Después de que tres subprocesos de 2 elementos han sido procesados por cada subproceso, el tamaño del trozo se incrementa de nuevo a 3 elementos por porción, y así sucesivamente. Al menos esta es la forma en que funciona de acuerdo con Dixin Yan, (consulte la sección de partición de Chunk) que trabaja para Microsoft.
Por cierto, la herramienta de visualización agradable en su blog parece ser el Concurrency Visualizer profile tool. El docs for this tool afirma que se puede usar para localizar cuellos de botella de rendimiento, infrautilización de CPU, contención de hilos, migración de hilos cruzados, retrasos de sincronización, actividad de DirectX, áreas de E/S superpuestas y otra información. Proporciona vistas de datos gráficos, tabulares y textuales que muestran las relaciones entre los hilos en una aplicación y el sistema como un todo.
Otros recursos:
MSDN: Custom Partitioners for PLINQ and TPL
Part 5: Parallel Programming - Optimizing PLINQ por Joseph Albahari
- 1. Cuándo usar la clase o interfaz abstracta?
- 2. Cuándo deberíamos usar la clase y cuándo no debemos
- 3. Cuándo usar un módulo y cuándo usar una clase
- 4. Cómo y cuándo usar una clase abstracta
- 5. Cuándo usar una clase en VBA?
- 6. ¿Cuándo y por qué deberíamos usar la clase System.ComponentModel.Container?
- 7. php: ¿Cuándo usar la clase abstracta y de interfaz?
- 8. En Objective-C, ¿cuándo debería usar métodos de clase y cuándo debería usar métodos de instancia?
- 9. Cuándo usar interfaces o clases abstractas? Cuándo usar ambos?
- 10. Cuándo usar undef_method, y cuándo usar remove_method?
- 11. Cuándo usar Ruby vs Cuándo usar PHP
- 12. Cuándo usar Pepino y cuándo usar RSpec?
- 13. cuándo usar Tarea y cuándo usar Subproceso?
- 14. Cuándo usar categorías y cuándo usar subclases?
- 15. ¿Cuándo deberíamos usar scala.util.DynamicVariable?
- 16. ¿Cuándo usar == y cuándo usarlo?
- 17. Mercurial: cuándo usar la actualización
- 18. cuándo usar la función htmlspecialchars()?
- 19. Cuándo usar eventos?
- 20. Cuándo usar self en las propiedades de clase?
- 21. ¿Cuándo debería usar una estructura en lugar de una clase?
- 22. En Python, ¿cuándo debería usar una clase meta?
- 23. ¿Cuándo debería usar una clase local en Java?
- 24. ¿Cuándo debería usar CompiledQuery?
- 25. ¿Cuándo se debe usar la instrucción Using?
- 26. Cuándo usar tipos básicos (Entero, Cadena), y cuándo escribir una nueva clase?
- 27. Cuándo usar Requirejs y cuándo usar javascript incluido?
- 28. ¿Cuándo debe usar JCR y cuándo debe usar JPA/RDBMS?
- 29. Cuándo usar Class.isInstance() y cuándo usar el operador instanceof?
- 30. Cuándo usar y cuándo no usar Try Catch Finally
El rangeSize predeterminado es uno para Partitioner.Create(). Por lo tanto, la partición es la misma para ambos ejemplos de código. A menos que Partitioner.Create (0, Input.Length, i); donde i> 1, todavía tendrá el mismo número de hilo. – Pingpong