Java: Come implementare il Multi-Threading in un algoritmo di ricerca delle dimensioni della cartella ricorsiva?


Quindi, ho già sviluppato una versione a thread singolo del finder delle dimensioni della cartella, ma per renderlo più interessante volevo migliorare la sua velocità e, auspicabilmente, sviluppare la mia comprensione dei processi multi-thread. Tuttavia dopo ~ 30 revisioni sembrava sempre esserci un problema, se fosse:
- Che il thread principale ha stampato il risultato prima che tutti i thread fossero eseguiti
- Il tipo lungo traboccava quando non avrebbe dovuto (possibile doppio conteggio forse)
- Il multi-threaded la versione richiede più tempo della versione a thread singolo

Sono in perdita, non lo so se un tale problema non è adatto per il multi-threading o se lo sto sbagliando. Ho inserito la mia revisione più "riuscita" di seguito.

Mi rendo conto che tecnicamente sta iniziando a unirsi immediatamente al thread di lavoro, rendendolo quasi peggiore del singolo calpestio. Tuttavia è l'unico modo in cui ho ottenuto il thread principale per visualizzare il risultato corretto.

Quindi il mio principale il problema è far sì che il thread di lavoro si unisca solo alla fine, facendolo esplorare tutte le sottocartelle in parallelo, quindi unendosi al thread principale per visualizzare il risultato corretto.

package sizeBrowserCode;

import java.io.File;
import java.io.FileWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class Main {
static long lengthy;
static Thread worker;
static long sum;

private static long getLength() {
    return Main.lengthy;
}

private static void setLength(long var) {
    Main.lengthy=var;
}

private static long getFolderSize(File folder) {
    long length=0;
    File[] files = folder.listFiles();

    int count = files.length;

    for (int i = 0; i < count; i++) {
        if (files[i].isFile()) {
            length += files[i].length();
        }
        else {
            length += getFolderSize(files[i],true);
        }
    }
    System.out.println(folder+" // "+length);

    return length;
}

private static long getFolderSize(File folder,boolean multiThreaded) {
    if(multiThreaded) {
        long length;
        worker=new Thread(new Runnable() {
             public void run() {

                setLength(getFolderSize(folder));
                 }
                });
            worker.start();
            try {
                worker.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            length=getLength();
        return length;

    }else {
        return getFolderSize(folder);
    }
}


public static String convert_Bytes(long bytes,String prefered_Unit) {
    prefered_Unit=prefered_Unit.toLowerCase().trim();
    switch (prefered_Unit) {
    case "b": return (bytes+" Bytes");
    case "kb": return (bytes/1024+" Kilobytes");
    case "mb": return (bytes/Math.pow(1024,2)+" Megabytes");
    case "gb": return (bytes/Math.pow(1024,3)+" Gigabytes");
    case "tb": return (bytes/Math.pow(1024,4)+" Terabytes");
    default:System.out.println("Incorrect notation; Please use\nb\nkb\nmb\ngb\ntb");
            System.exit(0);
            return null;

    }
}

public static String convert_Bytes(long bytes) {
    double Kb=0;
    double Mb=0;
    double Gb=0;
    double Tb=0;
    String result;
    if (bytes>=1024) {
        Kb=bytes/1024;
        bytes=0;
        result=" Kilobytes";
        if(Kb>=1024) {
            Mb=Kb/1024;
            Kb=0;
            result=" Megabytes";
            if(Mb>=1024) {
                Gb=Mb/1024;
                Mb=0;
                result=" Gigabytes";
                if(Gb>=1024) {
                    Tb=Gb/1024;
                    Gb=0;
                    result=" Terabyte";
                }
            }
        }
    }else {
        result=" Bytes";
    }
    double sum=bytes+Mb+Gb+Tb;
    return (sum+result);
}

public static void main(String[] args) {

    String chosen_Folder =args[0];
    String prefered_Unit;
    String full_Size;
    try {
        prefered_Unit =args[1];
    }catch (Exception e) {
        prefered_Unit=null;
    }

    String local_Folder=System.getProperty("user.dir");
    File full_Path;
    String backslash   ="\\";
    String forwardslash="/";
    String seperater;
    if(System.getProperty("os.name").toLowerCase().indexOf("win")>=0) {
        seperater=backslash;
    }else {
        seperater=forwardslash;
    }
    full_Path=new File(local_Folder+seperater+chosen_Folder);



    System.out.println(full_Path);
    long startTime =System.nanoTime();
    if(prefered_Unit!=null) {
        full_Size=convert_Bytes(getFolderSize(full_Path),prefered_Unit);

    }else {
        full_Size=convert_Bytes(getFolderSize(full_Path));
    }
    long endTime =System.nanoTime();

    System.out.println("The size of "+chosen_Folder+" is: "+full_Size);
    System.out.println("Took "+TimeUnit.NANOSECONDS.toSeconds(endTime-startTime)+" seconds to execute.");
    File size_Indicator = new File(full_Path+seperater+"FileSize.txt");
    try {
    size_Indicator.createNewFile();
    FileWriter writer = new FileWriter(size_Indicator);
    writer.write(full_Size);
    writer.close();
    }catch(Exception e) {
        System.err.println(e);
    }

}

}

Author: Percy Jackson, 2018-06-11

1 answers

Solo per completare altre risposte.

Cerca di evitare di usare

worker = new Thread(new Runnable() {
    ...
  }

Usa invece un Esecutore. Sono molto più facili da usare, da programmare, da eseguire e da ottenere i loro risultati. Inoltre si prendono cura del pool di thread e di altri overhead che hai.

Leggi questo .

Gli esecutori sono disponibili da Java 5 e sono parte integrante di qualsiasi JVM.

 1
Author: The Impaler, 2018-06-11 17:16:32