Come posso dire a una macchina multi-core/multi-CPU di elaborare le chiamate di funzione in un ciclo in parallelo?

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

  •  09-06-2019
  •  | 
  •  

Domanda

Attualmente sto progettando un'applicazione che ha un modulo che caricherà grandi quantità di dati da un database e li ridurrà a un insieme molto più piccolo mediante vari calcoli a seconda delle circostanze.

Molte delle operazioni più intensive si comportano in modo deterministico e si presterebbero all'elaborazione parallela.

A patto di avere un ciclo che itera su un gran numero di blocchi di dati in arrivo dal db e per ognuno chiama una funzione deterministica senza effetti collaterali, come potrei fare in modo che il programma non aspetti il ​​ritorno della funzione ma piuttosto imposti verranno avviate le prossime chiamate, in modo che possano essere elaborate in parallelo?Un approccio ingenuo per dimostrare il principio mi basterebbe per ora.

Ho letto il documento MapReduce di Google e anche se potrei utilizzare il principio generale in diversi punti, per ora non prenderò di mira cluster di grandi dimensioni, piuttosto sarà una singola macchina multi-core o multi-CPU per la versione 1.0 .Quindi al momento non sono sicuro di poter effettivamente utilizzare la libreria o di dover creare io stesso una versione base semplificata.

Sono in una fase iniziale del processo di progettazione e finora sto prendendo di mira C-qualcosa (per i bit critici sulla velocità) e Python (per i bit critici sulla produttività) come miei linguaggi.Se ci fossero ragioni convincenti, potrei cambiare, ma finora sono soddisfatto della mia scelta.

Tieni presente che sono consapevole del fatto che potrebbe essere necessario più tempo per recuperare il blocco successivo dal database rispetto all'elaborazione di quello corrente e l'intero processo sarebbe quindi legato a I/O.Tuttavia, per ora presumo che non lo sia e in pratica utilizzerei un cluster db o la memorizzazione nella cache della memoria o qualcos'altro per non essere vincolato all'I/O a questo punto.

È stato utile?

Soluzione

Potrei perdermi qualcosa qui, ma sembra abbastanza semplice usando pthreads.

Configura un piccolo pool di thread con N thread al suo interno e disponi di un thread per controllarli tutti.

Il thread principale si trova semplicemente in un ciclo che fa qualcosa del tipo:

  1. Ottieni blocco di dati dal DB
  2. Trova il prossimo thread libero Se nessun thread è libero, attendi
  3. Consegnare il pezzo al thread di lavoro
  4. Torna indietro e ottieni il pezzo successivo dal DB

Nel frattempo i thread di lavoro si siedono e fanno:

  1. Contrassegnarmi come libero
  2. Aspetta che il thread mast mi fornisca un pezzo di dati
  3. Elaborare il blocco di dati
  4. Contrassegnarmi di nuovo come libero

Il metodo con cui lo implementi può essere semplice come due array controllati da mutex.Uno contiene i thread utilizzati (il pool di thread) e l'altro indica se ciascun thread corrispondente è libero o occupato.

Modifica N a tuo piacimento...

Altri suggerimenti

Bene, se .net è un'opzione, ci hanno messo molti sforzi Calcolo parallelo.

Se hai ancora intenzione di utilizzare Python, potresti dare un'occhiata a in lavorazione.Utilizza processi anziché thread per il calcolo parallelo (grazie a Python GIL) e fornisce classi per distribuire "elementi di lavoro" su diversi processi.Usando la classe pool, puoi scrivere codice come il seguente:

import processing

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

Questa è una versione parallela di itertools.imap, che distribuisce le chiamate ai processi.Puoi anche utilizzare i metodi apply_async del pool e memorizzare gli oggetti risultato pigri in un elenco:

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

Per ulteriori riferimenti, cfr la documentazione della classe Pool.

Trabocchetti:

  • l'elaborazione utilizza fork(), quindi devi stare attento su Win32
  • gli oggetti trasferiti tra processi devono essere selezionabili
  • se i lavoratori sono relativamente veloci, puoi modificare la dimensione del pezzo, ad es.il numero di elementi di lavoro inviati a un processo di lavoro in un batch
  • elaborazione.Pool utilizza un thread in background

Puoi implementare l'algoritmo di Google Riduci mappa senza avere macchine fisicamente separate.Considera solo ciascuna di quelle "macchine" come "thread". I thread vengono distribuiti automaticamente su macchine multi-core.

Se stai lavorando con un compilatore che lo supporterà, suggerirei di dare un'occhiata a http://www.openmp.org Per un modo di annotare il tuo codice in modo tale che alcuni loop siano paralleli.

Fa anche molto di più e potresti trovarlo molto utile.

La loro pagina web riporta che gcc4.2 supporterà openmp, ad esempio.

Lo stesso pool di thread viene utilizzato in Java.Ma i thread nei threadpool sono serializzabili e inviati ad altri computer e deserializzati per essere eseguiti.

Ho sviluppato una libreria MapReduce per l'utilizzo multi-thread/multi-core su un singolo server.Tutto è curato dalla libreria e l'utente deve solo implementare Map e Reduce.È posizionata come libreria Boost, ma non è ancora accettata come libreria formale.Guardare http://www.craighenderson.co.uk/mapreduce

Potresti essere interessato ad esaminare il codice di libdispatch, che è l'implementazione open source di Grand Central Dispatch di Apple.

Anche il TBB o boost::mpi di Intel potrebbe interessarti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top