¿Cómo le digo a una máquina multinúcleo/multi-CPU que procese llamadas a funciones en un bucle en paralelo?

StackOverflow https://stackoverflow.com/questions/56769

  •  09-06-2019
  •  | 
  •  

Pregunta

Actualmente estoy diseñando una aplicación que tiene un módulo que cargará grandes cantidades de datos de una base de datos y los reducirá a un conjunto mucho más pequeño mediante varios cálculos según las circunstancias.

Muchas de las operaciones más intensivas se comportan de manera determinista y se prestarían a un procesamiento paralelo.

Siempre que tenga un bucle que itere sobre una gran cantidad de fragmentos de datos que llegan de la base de datos y para cada uno llame a una función determinista sin efectos secundarios, ¿cómo haría para que el programa no espere a que regrese la función sino que establezca ¿Las próximas llamadas van para que puedan procesarse en paralelo?Un enfoque ingenuo para demostrar el principio me bastaría por ahora.

He leído el artículo MapReduce de Google y, si bien podría usar el principio general en varios lugares, por ahora no me centraré en grupos grandes, sino que será una única máquina de múltiples núcleos o múltiples CPU para la versión 1.0. .Actualmente, no estoy seguro de si realmente puedo usar la biblioteca o si tendría que crear una versión básica simplificada yo mismo.

Estoy en una etapa temprana del proceso de diseño y hasta ahora estoy apuntando a C-algo (para los bits críticos de velocidad) y Python (para los bits críticos de productividad) como mis lenguajes.Si hay razones de peso, podría cambiar, pero hasta ahora estoy satisfecho con mi elección.

Tenga en cuenta que soy consciente del hecho de que podría llevar más tiempo recuperar el siguiente fragmento de la base de datos que procesar el actual y todo el proceso estaría vinculado a E/S.Sin embargo, asumiría por ahora que no lo es y, en la práctica, usaría un clúster de base de datos o almacenamiento en caché de memoria o algo más para no estar vinculado a E/S en este momento.

¿Fue útil?

Solución

Puede que me esté perdiendo algo aquí, pero esto parece bastante sencillo usando pthreads.

Configure un pequeño grupo de subprocesos con N subprocesos y tenga un subproceso para controlarlos a todos.

El hilo maestro simplemente se encuentra en un bucle y hace algo como:

  1. Obtener fragmento de datos de la base de datos
  2. Buscar el siguiente hilo libre Si no hay ningún hilo libre entonces espera
  3. Entregar el trozo al subproceso del trabajador
  4. Regrese y obtenga el siguiente fragmento de DB

Mientras tanto, los hilos de trabajo se sientan y hacen:

  1. Marcarme como libre
  2. Espere a que el hilo principal me proporcione una gran cantidad de datos.
  3. Procesar la porción de datos
  4. Marcarme como libre otra vez

El método mediante el cual implementar esto puede ser tan simple como dos matrices controladas por mutex.Uno tiene los hilos trabajados (el threadpool) y el otro indica si cada hilo correspondiente está libre u ocupado.

Modifica N a tu gusto...

Otros consejos

Bueno, si .net es una opción, se han esforzado mucho en Computación paralela.

Si todavía planeas usar Python, quizás quieras echar un vistazo a Procesando.Utiliza procesos en lugar de subprocesos para la computación paralela (debido a Python GIL) y proporciona clases para distribuir "elementos de trabajo" en varios procesos.Usando la clase pool, puedes escribir código como el siguiente:

import processing

def worker(i):
    return i*i
num_workers = 2
pool = processing.Pool(num_workers)
result = pool.imap(worker, range(100000))

Esta es una versión paralela de itertools.imap, que distribuye llamadas a procesos.También puedes usar los métodos apply_async del grupo y almacenar objetos de resultados diferidos en una lista:

results = []
for i in range(10000):
    results.append(pool.apply_async(worker, i))

Para mayor referencia, ver la documentación de la clase Pool.

Problemas:

  • el procesamiento usa fork(), por lo que debes tener cuidado en Win32
  • Los objetos transferidos entre procesos deben ser decapables.
  • si los trabajadores son relativamente rápidos, puede modificar el tamaño del fragmento, es decir,la cantidad de elementos de trabajo enviados a un proceso de trabajo en un lote
  • Processing.Pool utiliza un hilo de fondo

Puedes implementar el algoritmo de Google. Mapa reducido sin tener máquinas físicamente separadas.Solo considere cada una de esas "máquinas" como "hilos". Los subprocesos se distribuyen automáticamente en máquinas múltiples.

Si está trabajando con un compilador que lo admita, le sugiero que eche un vistazo a http://www.openmp.org Para una forma de anotar su código de tal manera que ciertos bucles sean paralelos.

También hace mucho más y puede que le resulte muy útil.

Su página web informa que gcc4.2 admitirá openmp, por ejemplo.

El mismo grupo de subprocesos se utiliza en Java.Pero los subprocesos en los grupos de subprocesos son serializables, se envían a otras computadoras y se deserializan para ejecutarse.

He desarrollado una biblioteca MapReduce para uso multiproceso/multinúcleo en un solo servidor.La biblioteca se encarga de todo y el usuario solo tiene que implementar Map y Reduce.Está posicionada como una biblioteca Boost, pero aún no es aceptada como una biblioteca formal.Verificar http://www.craighenderson.co.uk/mapreduce

Quizás le interese examinar el código de libdispatch, que es la implementación de código abierto de Grand Central Dispatch de Apple.

TBB o boost::mpi de Intel también podrían ser de su interés.

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