Come ridimensionare i thread in base ai core della CPU?


107

Voglio risolvere un problema matematico con più thread in Java. il mio problema di matematica può essere suddiviso in unità di lavoro, che voglio risolvere in più thread.

Non voglio avere una quantità fissa di thread che ci lavorano, ma invece una quantità di thread corrispondente alla quantità di core della CPU. Il mio problema è che non sono riuscito a trovare un semplice tutorial su Internet per questo. Tutto quello che ho trovato sono esempi con thread fissi.

Come si può fare? Potete fornire esempi?

Risposte:


120

È possibile determinare il numero di processi disponibili per Java Virtual Machine utilizzando il metodo Runtime statico, availableProcessors . Dopo aver determinato il numero di processori disponibili, creare quel numero di thread e suddividere il lavoro di conseguenza.

Aggiornamento : per chiarire ulteriormente, un thread è solo un oggetto in Java, quindi puoi crearlo proprio come creeresti qualsiasi altro oggetto. Quindi, diciamo che chiami il metodo sopra e scopri che restituisce 2 processori. Eccezionale. Ora puoi creare un ciclo che genera un nuovo thread e divide il lavoro per quel thread e spegne il thread. Ecco alcuni psuedocodici per dimostrare cosa intendo:

int processors = Runtime.getRuntime().availableProcessors();
for(int i=0; i < processors; i++) {
  Thread yourThread = new AThreadYouCreated();
  // You may need to pass in parameters depending on what work you are doing and how you setup your thread.
  yourThread.start();
}

Per ulteriori informazioni sulla creazione del tuo thread, vai a questo tutorial . Inoltre, potresti voler esaminare il pool di thread per la creazione dei thread.


17
Questo è fondamentalmente corretto, ma attenzione alle prestazioni sui processori commercializzati con "hyper-threading" di Intel. Su un quad-core, questo restituirà 8 invece di 4, ma le tue prestazioni potrebbero effettivamente iniziare a diminuire dopo 4 thread, quindi i miei benchmark me lo dicono :)
xcut

Ciao, ok, non sapevo, che questo è possibile. ma quando divido un'attività in più unità di lavoro e ho bisogno di una soluzione per tutte le parti per la fase di lavoro finale, come viene eseguita? Quando ho diversi "yourThreads" come posso usare join () per questo, perché non vedo, come questi diversi thread sono distinguibili? :) A proposito: il tuo collegamento al pool di thread mi ha portato a ibm.com/developerworks/library/j-jtp0730.html :)
Andreas Hornig

5
Guarda l'esempio qui: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/… Ti dirà un modo più semplificato per creare e gestire il pool di thread ... Potrebbe sembrare all'inizio è più complicato, ma come con la maggior parte delle cose, è più complicato perché se fosse più semplice avresti semplicemente raggiunto i limiti prima.
Bill K

62

Probabilmente vorrai dare un'occhiata al framework java.util.concurrent anche per queste cose. Qualcosa di simile a:

ExecutorService e = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// Do work using something like either
e.execute(new Runnable() {
        public void run() {
            // do one task
        }
    });

o

    Future<String> future = pool.submit(new Callable<String>() {
        public String call() throws Exception {
            return null;
        }
    });
    future.get();  // Will block till result available

Questo è molto più bello che gestire i tuoi pool di thread, ecc.


Ciao DaveC, hmmm, non lo sapevo prima, quindi darò un'occhiata a questo. E può essere ridimensionato in base ai core disponibili della CPU? Perché non riesco a vederlo in voi brevi esempi. Cordiali saluti, Andreas
Andreas Hornig

3
java.util.concurrent è altamente scalabile
Kristopher Ives il

4
Un pool di dimensioni fisse con il numero di processori disponibili è spesso ottimale per i processi associati alla CPU. Il primo esempio qui è tutto ciò che devi fare.
Peter Lawrey

1
Come affermato nel primo commento della risposta accettata, sarebbe meglio utilizzare la metà del numero di "Processori" segnalati, per due motivi: 1. se si dispone di hyper-threading, il numero reale di processori è la metà di quanto riportato e 2. lascia una certa potenza di elaborazione per il funzionamento del resto del sistema (sistema operativo e altri programmi).
Matthieu

10

Opzione 1:

newWorkStealingPool daExecutors

public static ExecutorService newWorkStealingPool()

Crea un pool di thread che ruba il lavoro utilizzando tutti i processori disponibili come livello di parallelismo di destinazione.

Con questa API, non è necessario trasferire il numero di core a ExecutorService.

Implementazione di questa API da grepcode

/**
     * Creates a work-stealing thread pool using all
     * {@link Runtime#availableProcessors available processors}
     * as its target parallelism level.
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

Opzione 2:

newFixedThreadPool API da Executorso other newXXX constructors, che restituisceExecutorService

public static ExecutorService newFixedThreadPool(int nThreads)

sostituire nThreads con Runtime.getRuntime().availableProcessors()

Opzione 3:

ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue)

passa Runtime.getRuntime().availableProcessors()come parametro a maximumPoolSize.



4

Il modo standard è il metodo Runtime.getRuntime (). AvailableProcessors (). Sulla maggior parte delle CPU standard avrai restituito il numero di thread ottimale (che non è il numero di core della CPU effettivo) qui. Quindi questo è quello che stai cercando.

Esempio:

ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

NON dimenticare di chiudere il servizio esecutore in questo modo (o il tuo programma non verrà chiuso):

service.shutdown();

Ecco solo una breve descrizione di come impostare un codice MT basato sul futuro (offtopico, per illustrazione):

CompletionService<YourCallableImplementor> completionService = 
    new ExecutorCompletionService<YourCallableImplementor>(service);
    ArrayList<Future<YourCallableImplementor>> futures = new ArrayList<Future<YourCallableImplementor>>();
    for (String computeMe : elementsToCompute) {
        futures.add(completionService.submit(new YourCallableImplementor(computeMe)));
    }

Quindi devi tenere traccia di quanti risultati ti aspetti e recuperarli in questo modo:

try {
  int received = 0;
  while (received < elementsToCompute.size()) {
     Future<YourCallableImplementor> resultFuture = completionService.take(); 
     YourCallableImplementor result = resultFuture.get();
     received++; 
  }
} finally {
  service.shutdown();
}

2
la chiamata di arresto dovrebbe essere messa in prova finalmente
Christophe Roussy

1
@ChristopheRoussy hai ragione, ho modificato lo snippet di conseguenza, grazie!
fl0w

3

Nella classe Runtime, c'è un metodo chiamato availableProcessors (). Puoi usarlo per capire quante CPU hai. Poiché il tuo programma è vincolato alla CPU, probabilmente vorrai avere (al massimo) un thread per CPU disponibile.


Ciao Jason ed Eric (uso un commento per entrambe le tue risposte, perché è sostanzialmente lo stesso). ok, è bello controllare, ma questa sarebbe la prima parte. Quando ho il conteggio dei core, devo avere i thread variabili come questa quantità di core. Ho provato questo esempio prima di openbook.galileodesign.de/javainsel5/… (tedesco!) E utilizza un thread fisso. Ma voglio avere la stessa programmazione utilizzando 2 core in un ambiente dual-core e 4 core in un ambiente quad-core. Non voglio cambiarlo manualmente. È possibile? GRAZIE! :)
Andreas Hornig il

@Andreas - Guarda gli aggiornamenti che ho apportato al mio post. Penso che aiuterà a chiarire la questione.
JasCav
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.