2012-04-14 14 views
6

Nel mio progetto sto costruendo un framework di esecuzione Java che riceve richieste di lavoro da un client. Il lavoro (di dimensioni variabili) è suddiviso in un insieme di attività e quindi accodato per l'elaborazione. Esistono code separate per elaborare ogni tipo di attività e ogni coda è associata a un ThreadPool. ThreadPools è configurato in modo tale che le prestazioni generali del motore siano ottimali.Lavoro/Task Stealing ThreadPoolExecutor

Questo progetto ci aiuta a bilanciare il carico delle richieste in modo efficace e le richieste di grandi dimensioni non finiscono per eseguire il hogging delle risorse di sistema. Tuttavia, a volte la soluzione diventa inefficace quando alcune delle code sono vuote e il rispettivo pool di thread rimane inattivo.

Per migliorarlo, stavo pensando di implementare una tecnica di furto di lavoro/attività in modo che la coda pesantemente caricata possa ottenere aiuto dagli altri ThreadPools. Tuttavia, ciò potrebbe richiedere l'implementazione del mio Executor poiché Java non consente l'associazione di più code a un ThreadPool e non supporta il concetto di furto del lavoro.

Leggi di Fork/Join ma non mi sembra adatto per le mie esigenze. Qualsiasi suggerimento o modo alternativo per costruire questa soluzione potrebbe essere molto utile.

Grazie Andy

+1

Si dovrebbe pensare a come mantenere tutte le CPU occupate. Non importa se alcuni dei tuoi thread sono inattivi se stai facendo il miglior uso delle tue CPU. –

+0

Se i pool di thread hanno tanti thread quanti sono i cpus, qualsiasi singolo pool di thread può "rubare" tutte le cpus anche se tutti gli altri pool di thread sono inattivi. –

+0

@PeterLawrey - è vero, ma se ci sono molti pool, allora si può avere scarso rendimento se tutti i thread in tutti i pool funzionano allo stesso tempo. – jtahlborn

risposta

1

si potrebbe implementare un'implementazione BlockingQueue personalizzato (penso che principalmente necessario implementare le offer() e take() metodi), che è sostenuto da una coda "primario" e 0 o più secondari code. take prende sempre dalla coda di backing principale se non vuota, altrimenti può tirare dalle code secondarie.

infatti, potrebbe essere meglio disporre di 1 pool in cui tutti i lavoratori hanno accesso a tutte le code, ma "preferiscono" una coda specifica. puoi trovare il tuo rapporto ottimale di lavoro assegnando priorità diverse a diversi lavoratori. in un sistema completamente caricato, i tuoi dipendenti dovrebbero lavorare con il rapporto ottimale. in un sistema sotto carico, i tuoi dipendenti dovrebbero essere in grado di dare una mano con altre code.

+0

Questa mi sembra una buona idea che mi sto appoggiando a provare con un POC. –

2

Avete considerato il ForkJoinPool? Il framework fork-join è stato implementato in un modo modulare, quindi è possibile utilizzare solo il pool di thread di work-stealing.

+1

Leggi l'API ma non riesco ancora a capire come sia diverso dal normale ThreadPoolExecutor. Forse mancano alcuni aspetti più belli lì. –

+0

Sì. Capisco, quello che hai è in effetti uno schema di partizionamento che ora vuoi rendere flessibile, lasciare che i limiti della partizione si spostino in base al carico di lavoro. "Il furto del lavoro" può essere un termine più specializzato per schemi che implicano una granulazione di attività fine: un'attività che esegue su un thread genera attività secondarie e le spinge verso la propria deque, in modo che altri thread possano rubarne il lavoro. Quindi, se fai una ricerca con il termine "partizionamento del pool di thread" troverai qualcosa di adatto al tuo caso. –

2

Java 8 ha metodi di fabbrica e di utilità per quello nella classe Executors. Esiste un'implementazione di un pool di thread di work-stealing (here) che, credo, sia esattamente ciò che si desidera.

+0

Solo lo svantaggio che vedo con questo è che crea nuovi ForkJoinThread su richiesta invece di prendere in prestito questi thread da un pool globale - può essere un pool o un pool comune che il client può passare. –