Visualizzazione dei risultati da 1 a 6 su 6
  1. #1

    Evitare di riscrivere del codice con RecurTask e ForkJoinPool

    C'è una classe Sum che uso spesso con questi metodi:

    codice:
    import java.util.concurrent.*;  
     class Sum extends RecursiveTask<Double> { 
     final int seqThresHold = 500; 
     double[] data;  
     int start, end; 
     Sum(double[] vals, int s, int e ) { 
        data = vals; 
        start = s; 
        end = e; 
      } 
     protected Double compute() { 
        double sum = 0; 
     if((end - start) < seqThresHold) { 
          for(int i = start; i < end; i++) sum += data[i]; 
        } 
        else { 
          int middle = (start + end) / 2; 
     Sum subTaskA = new Sum(data, start, middle); 
          Sum subTaskB = new Sum(data, middle, end); 
     subTaskA.fork(); 
          subTaskB.fork(); 
     sum = subTaskA.join() + subTaskB.join(); 
        } 
          return sum; 
      } 
    } 
     class RecurTaskDemo {  
      public static void main(String args[]) {  
        ForkJoinPool fjp = new ForkJoinPool(); 
     double[] nums = new double[5000]; 
     for(int i=0; i < nums.length; i++) 
          nums[i] = (double) (((i%2) == 0) ? i : -i) ; 
     Sum task = new Sum(nums, 0, nums.length); 
     double summation = fjp.invoke(task); 
     System.out.println("Summation " + summation); 
      }  
    }
    Il codice funziona ma è scomodo da utilizzare in quanto tutte le volte che devo apportare una modifica all'algoritmo che racchiude la classe (nell'esempio la somma di numeri di un vettore) mi devo portare dietro tutto il resto della classe. Per questo motivo vorrei creare una classe Sum magari rinominata con qualcosa di più originale (ad es. Multiprocessione, ScomposizioneParallela o qualcosa di originale, ecc...) che posso importare nel mio pakage all'occorrenza ed utilizzare in diverse circostanze. In sostanza mi serve un metodo che accetti in input un altro metodo sequenziale trasformabile con la tecnica della ricorsione in pura e semplice programmazione parallela.

    Qui sotto un mio tentativo che vi aiuta a capire come vorrei affrontare il problema che però non funziona:

    codice:
    import java.util.concurrent.*;
    
    class Sum extends RecursiveTask<Double> {
        final int seqThresHold = 1000;
        double[] data;
        int start, end;
    
        Sum(double[] vals, int s, int e) {
            data = vals;
            start = s;
            end = e;
        }
    
        protected Double compute() {
            double sum = 0;
            if ((end - start) < seqThresHold) {
                MetodoSomma.MetodoSomma(data, start, end);
            } else {
                int middle = (start + end) / 2;
                Sum subTaskA = new Sum(data, start, middle);
                Sum subTaskB = new Sum(data, middle, end);
                subTaskA.fork();
                subTaskB.fork();
                sum = subTaskA.join() + subTaskB.join();
            }
            return sum;
        }
    }
    
    class MeotodoSomma{
        private void MetodoSomma(double[] data, int start, int end) {
            double sum = 0;
            for (int i = start; i < end; i++) {
                sum += data[i];
                for (int j = start; j < end; j++) {
                    sum += data[j];
                    sum -= data[j];
                }
            }
        }
    }
    
    class RecurTaskDemo {
        public static void main(String args[]) {
            double[] nums = new double[4000];
            for (int i = 0; i < nums.length; i++)
                nums[i] = (double) (((i % 2) == 0) ? i : -i);
            ForkJoinPool fjp = new ForkJoinPool();
            Sum task = new Sum(nums, 0, nums.length);
            double summation = fjp.invoke(task);
            System.out.println("Summation " + summation);
        }
    }
    Detto in modo più semplice vorrei programmare in modo sequenziale creando un metodo che trasforma il mio metodo sequenziale in programmazione parallela senza dover estendere tutte le volte RecursiveTask, istanziare un ForkJoinPool, ecc...
    Per essere ancora più chiaro mi servirebbe un sistema qualsiasi per evitare di riscrivere tutte le volte il contenuto di 'else'. Vorrei dividere il codice che regola il calcolo (somma di numeri) da quello che esegue la scomposizione del carico di lavoro su più processori (RecursiveTask, ForkJoinPool).





    Più pratica in futuro...

  2. #2
    Utente di HTML.it L'avatar di kuarl
    Registrato dal
    Oct 2001
    Messaggi
    1,093
    al di la del fatto che quando vedo campi e metodi senza un modificatore di visibilità provo la stessa sensazione di unghiate sopra la lavagna, io fare così:

    codice:
    public void parallelizzaEdEsegui(Collection<? extends RecursiveTask<Double>> tasks) {
       ForkJoinPool fjp = new ForkJoinPool();
       for(RecursiveTask<Double> t : tasks)
          fjp.invoke(t);
    }
    le tue classi (... e anche qui sorvolo) che eseguono conti estendono tutte RecursiveTask. Quindi puoi instanziarle, infilarle in una collection qualsiasi (lista, mappa, set o che ne sò) e darla in pasto a questo metodo...

    edit:
    alternativamente, usando varargs:
    codice:
    public void parallelizzaEdEsegui(RecursiveTask<Double>... tasks) {
      ForkJoinPool fjp = new ForkJoinPool();
       for(RecursiveTask<Double> t : tasks)
          fjp.invoke(t);
    }
    come prima ma invece di buttare tutto in una collection devi fare una roba tipo:
    codice:
    parallelizzaEdEsegui(new Sum(nums,0, nums.length), new Sum(nums,1, nums.length), ... );


    ovvero darle come parametro alla funzione quante volte vuoi...
    Ultima modifica di kuarl; 19-01-2014 a 16:24

  3. #3
    Quote Originariamente inviata da kuarl Visualizza il messaggio
    al di la del fatto che quando vedo campi e metodi senza un modificatore di visibilità provo la stessa sensazione di unghiate sopra la lavagna, io fare così:

    codice:
    public void parallelizzaEdEsegui(Collection<? extends RecursiveTask<Double>> tasks) {
       ForkJoinPool fjp = new ForkJoinPool();
       for(RecursiveTask<Double> t : tasks)
          fjp.invoke(t);
    }
    le tue classi (... e anche qui sorvolo) che eseguono conti estendono tutte RecursiveTask. Quindi puoi instanziarle, infilarle in una collection qualsiasi (lista, mappa, set o che ne sò) e darla in pasto a questo metodo...

    edit:
    alternativamente, usando varargs:
    codice:
    public void parallelizzaEdEsegui(RecursiveTask<Double>... tasks) {
      ForkJoinPool fjp = new ForkJoinPool();
       for(RecursiveTask<Double> t : tasks)
          fjp.invoke(t);
    }
    come prima ma invece di buttare tutto in una collection devi fare una roba tipo:
    codice:
    parallelizzaEdEsegui(new Sum(nums,0, nums.length), new Sum(nums,1, nums.length), ... );


    ovvero darle come parametro alla funzione quante volte vuoi...
    Non capisco come dovrei modificare il codice e ho timore che tu ti sia dimenticato di portare fuori da Sum questo pezzo:

    codice:
    for (int i = start; i < end; i++) {
                    sum += data[i];
                    for (int j = start; j < end; j++) {
                        sum += data[j];
                        sum -= data[j];
                    }
                }
    Se riesci a farmi vedere l'esempio completo forse riesco a comprendere la tua idea.
    Più pratica in futuro...

  4. #4
    Io vorrei arrivare a scrivere questo:

    codice:
     package esempio;
    
    public class RecurTaskDemo {
    
        private static double Sum(double[] data, int start, int end) {
            double sum = 0;
            for (int i = start; i < end; i++) {
                sum += data[i];
            }
            return sum;
        }
    
        // ???
    
        public static void main(String args[]) {
    
            double[] nums = new double[4000];
            for (int i = 0; i < nums.length; i++)
                nums[i] = (double) (((i % 2) == 0) ? i : -i);
    
            double sum = Sum(nums, 0, 4000);
    
            // double sum = ... calcolo di sum usando tutti i core del mio pc
            
            System.out.println(sum);
    
        }
    
    }
    Più pratica in futuro...

  5. #5
    Utente di HTML.it L'avatar di kuarl
    Registrato dal
    Oct 2001
    Messaggi
    1,093
    no, continuo a non capire. Se vuoi trasformare codice single thread in multi thread devi riscrivere tutto. La bacchetta magica non esiste. Se si tratta solo di operazioni algebriche puoi valutare la possibilità di utilizzare librerie parallele, così non dovrai scrivertele da solo.

    Un esempio è openCL. Ti fornisce una libreria di funzioni per il calcolo parallelo che può essere eseguita sia su CPU sfruttando i vari core e set di istruzioni specialistici per queste operazioni, sia le GPU.

  6. #6
    peccato, darò un'occhiata a queste librerie, grazie mille
    Più pratica in futuro...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.