Autore Topic: Programmazione concorrente JAVA  (Letto 321 volte)

Offline tonno16

  • Utente storico
  • *****
  • Post: 1197
    • Mostra profilo
  • Dispositivo Android:
    moto g
  • Play Store ID:
    Diego Tonini
  • Sistema operativo:
    OpenSuse
Programmazione concorrente JAVA
« il: 31 Agosto 2014, 19:15:37 CEST »
Ho implementato una classe multuthread che esegue lo stesso compito ma spartendo il compito fra il numero di cpu.

Codice (Java): [Seleziona]
public class MultiThreadedScalarProductExecutor implements ScalarProductExecutor{

       
        private List<Worker> listWorkers = new ArrayList<>();
       
        private static class Sum {
                private double sum = 0;
               
                public synchronized void add(double partialSum){
                        sum+=partialSum;
                }
                public synchronized double getTotalSum(){
                        return sum;
                }
        }
       
        @Override
        public double scalarProduct(double[] v1, double[] v2) {
               
                int nCPU = Runtime.getRuntime().availableProcessors();
                int nValues = Math.round(v1.length/nCPU);
                int index = 0; 
                Sum totalSum = new Sum();
               
                for(int i=0;i<nCPU-1;i++){
                        Worker w = new Worker(v1,v2,index,index+nValues,totalSum);
                        listWorkers.add(w);
                        w.start();
                        index += nValues;
                }
               
                Worker w = new Worker(v1,v2,index,v1.length,totalSum);
                w.start();
               
                for(Worker worker : listWorkers){
                        try {
                                w.join();
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                }
               
                return totalSum.getTotalSum(); 
        }
       
       
        class Worker extends Thread {
               
                private double[] v1,v2;
                volatile int start,stop;
                private Sum sum;
               
                Worker(double[] v1, double[] v2,int start, int stop, Sum sum){
                        this.v1 = v1;
                        this.v2 = v2;
                        this.start = start;
                        this.stop = stop;
                        this.sum = sum;
                }
               
                @Override
                public void run(){
                        for (int i = start; i < stop; i++){
                                        sum.add(v1[i]*v2[i]);                          
                        }              
                }
                               
        }

}

il mio main:

Codice (Java): [Seleziona]
public static void main(String[] args) {
                // si decommenti il codice qui sotto
               
               
                int size = 100;
                double[] v1 = new double[size];
                double[] v2 = new double[size];
                for (int i=0; i<size;i++){
                        v1[i] = 10;
                        v2[i] = i;
                }
               
                long start;
                long finish;
               
                start = System.currentTimeMillis();
                System.out.println(new ScalarProductExecutor.Simple().scalarProduct(v1, v2));
                finish = System.currentTimeMillis();
                System.out.print(" monothread impiegato: "+(finish-start));
               
                start = System.currentTimeMillis();
                System.out.println("\n"+new MultiThreadedScalarProductExecutor().scalarProduct(v1, v2));
                finish = System.currentTimeMillis();
                System.out.print(" multi impiegato: "+(finish-start));
               
        }

ora vorrei sapere una cosa. Usiamo questo sistema in facoltà perchè richiesto nell' esercizio. Ora la stampa con una matrice da 100 impiega circa 1 millisecondo senza gestione dei thread, mentre impiega 3 millisecondi con la gestione multipla.

Aumentando il numero della matrice arrivo ad un ratio 1:6.

Dunque dove sta il vantaggio? mi sto confondendo io?

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Programmazione concorrente JAVA
« Risposta #1 il: 31 Agosto 2014, 19:43:49 CEST »
Usiamo questo sistema in facoltà perchè richiesto nell' esercizio. Ora la stampa con una matrice da 100 impiega circa 1 millisecondo senza gestione dei thread, mentre impiega 3 millisecondi con la gestione multipla.

Aumentando il numero della matrice arrivo ad un ratio 1:6.

Dunque dove sta il vantaggio? mi sto confondendo io?

Per sfruttare il multithreading occorre anche che il lavoro da svolgere si presti ad essere parallelizzato su più thread. Ci sono infatti classi di problemi (a dir la verità la maggioranza), che non lo sono. E quindi ecco che entra in gioco la legge di Amdahl ( Amdahl's law - Wikipedia, the free encyclopedia ) a guastare la festa.

Da quello che vedo il "lavoro" da svolgere è inferiore all'overhead indotto dal multi-threading (tu prova a non fare niente al thread e vedi quanto ci mette nei due casi: quel tempo è l'overhead). Probabilmente per il tipo di calcolo che stai facendo l'ideale sarebbero le istruzioni di tipo SIMD, ma non credo nemmeno ci sia il supporto nella Dalvik.

Per testare i benefici del multi-threading l'ideale sono gli algoritmi lunghi, ma con pochi accessi ai dati, così da minimizzare i miss dalla cache. Per esempio il calcolo delle prime N cifre di pigreco.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline tonno16

  • Utente storico
  • *****
  • Post: 1197
    • Mostra profilo
  • Dispositivo Android:
    moto g
  • Play Store ID:
    Diego Tonini
  • Sistema operativo:
    OpenSuse
Re:Programmazione concorrente JAVA
« Risposta #2 il: 31 Agosto 2014, 20:07:31 CEST »
Guarda. Purtroppo non ho capito quasi niente di quello che hai scritto.

Ho provato a usare matrici di dimensione 10000000 ma il metodo due è sempre più lento.
Non comprendo il perché debba avere una soluzione analoga nel mio corso di studi se poi si rivela pessima.


Post unito: 31 Agosto 2014, 20:12:08 CEST
Grazie comunque dell'ottima spiegazione
« Ultima modifica: 31 Agosto 2014, 20:12:08 CEST da tonno16, Reason: Merged DoublePost »

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Programmazione concorrente JAVA
« Risposta #3 il: 01 Settembre 2014, 08:39:12 CEST »
Ho provato a usare matrici di dimensione 10000000 ma il metodo due è sempre più lento.
Non comprendo il perché debba avere una soluzione analoga nel mio corso di studi se poi si rivela pessima.

Il problema è la natura del problema, non la sua dimensione. Parallelizzare ha un costo (overhead), dovuto alla gestione dei thread multipli. Se il lavoro del thread è paragonabile al costo di parallelizzazione, è chiaro che non hai vantaggi, ma svantaggi.

Diciamo che per il tuo problema specifico, avere thread multipli non porta vantaggi. Sarebbe da provare ad uscire dalla dalvik e farlo tutto con NDK per verificare se non è un problema del runtime Dalvik.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline tonno16

  • Utente storico
  • *****
  • Post: 1197
    • Mostra profilo
  • Dispositivo Android:
    moto g
  • Play Store ID:
    Diego Tonini
  • Sistema operativo:
    OpenSuse
Re:Programmazione concorrente JAVA
« Risposta #4 il: 01 Settembre 2014, 09:41:06 CEST »
Codice (Java): [Seleziona]
for(int i=0;i<nCPU-1;i++){
                        Worker w = new Worker(v1,v2,index,index+nValues,totalSum);
                        listWorkers.add(w);
                        w.start();
                        index += nValues;
                }

può essere forse porzione di codice? alla fine in ogni classe Worker passo i due vettori interi, per nCPU volte...