Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 20
  1. #1

    Velocizzare la fase di scrittura di un file su disco

    E' possibile velocizzare ulteriormente questo metodo?

    codice:
     private static void Scrivi(Object[][] matrice,
                String nome_file) {
            try {
                FileOutputStream file = new FileOutputStream(nome_file);
                PrintStream output = new PrintStream(file);
                for (int i = 0; i < matrice.length; i++) {
                    String riga = "";
                    for (int j = 0; j < matrice[0].length; j++) {
                        if (j < matrice[0].length - 1) {
                            riga = riga + matrice[i][j] + ",";
                        }
                        if (j == matrice[0].length - 1) {
                            riga = riga + matrice[i][j];
                        }
                    }
                    output.println(riga);
                    riga = "";
                }
            } catch (IOException e) {
                System.out.println("Errore nella scrittura del file .CSV");
                System.exit(1);
            }
        }
    Più pratica in futuro...

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da giannino1995 Visualizza il messaggio
    E' possibile velocizzare ulteriormente questo metodo?
    Sì, e anche abbastanza.
    Innanzitutto utilizzando una classe di I/O in grado di fare del "buffering". Alcune varianti:

    tue scritture -> PrintStream -> BufferedOutputStream -> FileOutputStream
    oppure
    tue scritture -> BufferedWriter -> OutputStreamWriter -> FileOutputStream

    Poi se vuoi comporre una riga intera per volta, certamente non usando la concatenazione delle stringhe ma usando direttamente un StringBuffer/StringBuilder. In alternativa (avendo un "buffering" al di sotto che aiuta), scrivere direttamente i pezzetti senza comporre alcuna stringa più grande.


    Ah, e sarebbe bene fare alla fine un bel flush() e poi il close(). Entrambi sull'oggetto di I/O più "esterno" che hai in quel momento.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Sì, e anche abbastanza.
    Innanzitutto utilizzando una classe di I/O in grado di fare del "buffering". Alcune varianti:

    tue scritture -> PrintStream -> BufferedOutputStream -> FileOutputStream
    oppure
    tue scritture -> BufferedWriter -> OutputStreamWriter -> FileOutputStream

    Poi se vuoi comporre una riga intera per volta, certamente non usando la concatenazione delle stringhe ma usando direttamente un StringBuffer/StringBuilder. In alternativa (avendo un "buffering" al di sotto che aiuta), scrivere direttamente i pezzetti senza comporre alcuna stringa più grande.


    Ah, e sarebbe bene fare alla fine un bel flush() e poi il close(). Entrambi sull'oggetto di I/O più "esterno" che hai in quel momento.



    Scrittura lenta: 18.74 secondi
    Scrittura veloce: 0.246 secondi



    P.S.: Più la dimensione cresce più il divario cresce, sembra impossibile!

    grazie andbin, sei il numero 1!

    Ho trovato lo script nel capitolo NIO del mio manuale ma la differenza è notevole!!!

    Ti devo chiedere 2 cose:

    1) Sapresti spiegarmi in modo semplice senza troppi giri di parole il motivo per cui il nuovo script è riesce ad essere più veloce?

    2) Con il nuovo codice si hanno dei contro oltre che dei pro?

    3) Si scrive prima nella ram e poi sul disco o direttamente sul disco con questi sistemi?

    4) Esiste qualcosa di ancora più veloce? Era questo che avevi in testa? (buttaci un occhio magari riesci a migliorarlo ancora... anche solo di qualche miliardesimo di nanosecondo... )

    Ecco il nuovo codice:

    codice:
    try (OutputStream fout = new BufferedOutputStream(
                    Files.newOutputStream(Paths.get(nome_file)))) {
                String riga = "";
                for (int i = 0; i < matrice.length; i++) {
                    riga = "";
                    for (int j = 0; j < matrice[0].length; j++) {
                        if (j < matrice[0].length - 1) {
                            riga = riga + matrice[i][j] + ",";
                        }
                        if (j == matrice[0].length - 1) {
                            riga = riga + matrice[i][j] + "\n";
                        }
                    }
                    fout.write(riga.getBytes());
                    riga = "";
                }
            } catch (InvalidPathException e) {
                System.out.println("URL scelto inesistente.");
                System.out.println("Path Error " + e);
            } catch (IOException e) {
                System.out.println("Errore nella scrittura del file .CSV");
                System.out.println("I/O Error: " + e);
            }
    lo lascio servisse a qualche altro forumisto di html.it.
    Ultima modifica di giannino1995; 21-01-2014 a 21:20
    Più pratica in futuro...

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da giannino1995 Visualizza il messaggio
    4) Esiste qualcosa di ancora più veloce? Era questo che avevi in testa?
    Ehm .... no, non era esattamente questo a cui pensavo. Per almeno 2 motivi.

    Prima avevo fatto l'esempio della "catena" di classi che si possono usare. All'esterno sarebbe meglio avere un PrintStream o un BufferedWriter (rivedi risposta #2).
    Quello che hai fatto tu, cioè usare direttamente uno "stream" e scrivere byte usando riga.getBytes() è di per sé tecnicamente corretto.
    Ma sarebbe stato meglio scrivere "a caratteri" (appunto PrintStream o BufferedWriter) perché è più chiaro ma oltretutto sotto sotto hanno sicuramente più possibilità di ottimizzare la scrittura.

    Come seconda cosa: hai continuato ad usare la "concatenazione" delle stringhe all'interno dei cicli for, cosa che in quel modo è inefficiente.
    Sarebbe meglio:
    - Usare direttamente StringBuffer/StringBuilder per comporre la riga.
    oppure
    - Visto che di "sotto" c'è una bufferizzazione, scrivere direttamente i pezzetti della riga, senza comporre una stringa unica.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Ho sostituito quel \n con un'altra cosa ma il codice scritto mi sembra già abbastanza veloce. Non ho capito cos'hai in mente PrintStream l'ho provato ed è molto lento rispetto al codice NIO che ho usato...
    Più pratica in futuro...

  6. #6
    Scrivere subito senza usare la variabile riga incrementa ulteriormente le performance. Pazzesco!!!

    codice:
    package prova;
    
    import java.io.BufferedOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.nio.file.Files;
    import java.nio.file.InvalidPathException;
    import java.nio.file.Paths;
    import java.security.NoSuchAlgorithmException;
    
    class Esempio {
    
        static void Stampa1(Object[][] matrice, String nome_file) {
            String lineSeparator = System.getProperty("line.separator");
            try (OutputStream fout = new BufferedOutputStream(
                    Files.newOutputStream(Paths.get(nome_file)))) {
                String riga = "";
                for (int i = 0; i < matrice.length; i++) {
                    riga = "";
                    for (int j = 0; j < matrice[0].length; j++) {
                        if (j < matrice[0].length - 1) {
                            riga = riga + matrice[i][j] + ",";
                        }
                        if (j == matrice[0].length - 1) {
                            riga = riga + matrice[i][j] + lineSeparator;
                        }
                    }
                    fout.write(riga.getBytes());
                    riga = "";
                }
            } catch (InvalidPathException e) {
                return;
            } catch (IOException e) {
                return;
            }
        }
    
        static void Stampa2(Object[][] matrice, String nome_file) {
            String lineSeparator = System.getProperty("line.separator");
            try (OutputStream fout = new BufferedOutputStream(
                    Files.newOutputStream(Paths.get(nome_file)))) {
                for (int i = 0; i < matrice.length; i++) {
                    for (int j = 0; j < matrice[0].length; j++) {
                        if (j < matrice[0].length - 1) {
                            fout.write((matrice[i][j] + ",").getBytes());
                        }
                        if (j == matrice[0].length - 1) {
                            fout.write((matrice[i][j] + lineSeparator).getBytes());
                        }
                    }
                }
            } catch (InvalidPathException e) {
                return;
            } catch (IOException e) {
                return;
            }
        }
    
        public static void main(String[] args) throws NoSuchAlgorithmException {
            int righe = 600;
            int colonne = 600;
            Object[][] matrice = new Object[righe][colonne];
            for (int i = 0; i < righe; i++) {
                for (int j = 0; j < colonne; j++) {
                    matrice[i][j] = "Indici della cella della matrice: i = " + i
                            + " j = " + j;
                }
            }
            long start = System.currentTimeMillis();
            Stampa1(matrice, "prova.csv");
            long fine = System.currentTimeMillis();
            long tempo = fine - start;
            System.out.println((double) tempo / 1000);
            long start2 = System.currentTimeMillis();
            Stampa2(matrice, "prova2.csv");
            long fine2 = System.currentTimeMillis();
            long tempo2 = fine2 - start2;
            System.out.println((double) tempo2 / 1000);
        }
    }


    ti dico solo una cosa:

    Output del programma:
    10.809
    0.967
    Più pratica in futuro...

  7. #7
    Utente di HTML.it L'avatar di Alex'87
    Registrato dal
    Aug 2001
    residenza
    Verona
    Messaggi
    5,802
    Non so quanti dati processi ma tutte quelle concatenazioni di stringhe sarebbero da evitare. In Java una stringa è un oggetto immutabile: ogni modifica comporta la creazione di una nuova stringa.
    Ad esempio,

    String s = "hello"; // prima stringa, "hello"
    s += "world"; // "world" è una stringa e "helloworld" è un'altra stringa ancora

    All'interno di un ciclo con tante iterazioni andrai a creazione migliaia e migliaia di stringhe che occupano solo memoria (che verrà poi liberata dal garbage collector, ma non è questo il punto.)

    Usa StringBuilder se devi concatenare *tante* stringhe (o StringBuffer se ti serve thread safe)
    SpringSource Certified Spring Professional | Pivotal Certified Enterprise Integration Specialist
    Di questo libro e degli altri (blog personale di recensioni libri) | ​NO M.P. TECNICI

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Lo vuoi capire che:

    a) stai comunque ancora usando la concatenazione delle stringhe, che così in un loop è inefficiente.
    b) non si dovrebbero fare catch con un banale return. Così, in generale, "zittisci" le eccezioni.
    c) per fare calcoli sui tempi che siano un po' attendibili, bisognerebbe ripetere il codice un po' di volte e prendere almeno la media dei tempi.

    ?


    Ti spiace provare esattamente questo:

    codice:
    import java.io.*;
    import java.nio.file.*;
    
    public class ProvaTempiScritturaMatrice {
        public static void main(String[] args) {
            int righe = 600;
            int colonne = 600;
            final Object[][] matrice = new Object[righe][colonne];
            for (int i = 0; i < righe; i++) {
                for (int j = 0; j < colonne; j++) {
                    matrice[i][j] = "Indici della cella della matrice: i = " + i
                            + " j = " + j;
                }
            }
    
            Runnable andbinCode = new Runnable() {
                public void run() {
                    try {
                        writeMatrix("prova.csv", matrice);
                    } catch (IOException e) {
                        System.out.println(e);
                    }
                }
            };
    
            Runnable gianninoCode = new Runnable() {
                public void run() {
                    Stampa2(matrice, "prova.csv");
                }
            };
    
            System.out.println("andbin code   : " + timeTest(andbinCode) + " millisecondi");
            System.out.println("giannino code : " + timeTest(gianninoCode) + " millisecondi");
        }
    
        public static double timeTest(Runnable r) {
            int count = 100;
            double milliSum = 0;
    
            for (int i = 0; i < count; i++) {
                long begin = System.nanoTime();
                r.run();
                long end = System.nanoTime();
                milliSum += (end - begin) / 1000000.0;
            }
    
            return milliSum  / count;
        }
    
    
        /*---- andbin ----*/
        public static void writeMatrix(String filename, Object[][] matrix) throws IOException {
            FileOutputStream fos = new FileOutputStream(filename);
            OutputStreamWriter osw = new OutputStreamWriter(fos);
            BufferedWriter bw = new BufferedWriter(osw);
    
            try {
                for (int r = 0; r < matrix.length; r++) {
                    for (int c = 0; c < matrix[r].length; c++) {
                        if (c > 0) {
                            bw.write(",");
                        }
    
                        bw.write(String.valueOf(matrix[r][c]));
                    }
    
                    bw.newLine();
                }
            } finally {
                try { bw.close(); } catch (IOException e) {}
            }
        }
    
    
        /*---- giannino1995 ----*/
        static void Stampa2(Object[][] matrice, String nome_file) {
            String lineSeparator = System.getProperty("line.separator");
            try (OutputStream fout = new BufferedOutputStream(
                    Files.newOutputStream(Paths.get(nome_file)))) {
                for (int i = 0; i < matrice.length; i++) {
                    for (int j = 0; j < matrice[0].length; j++) {
                        if (j < matrice[0].length - 1) {
                            fout.write((matrice[i][j] + ",").getBytes());
                        }
                        if (j == matrice[0].length - 1) {
                            fout.write((matrice[i][j] + lineSeparator).getBytes());
                        }
                    }
                }
            } catch (InvalidPathException e) {
                return;
            } catch (IOException e) {
                return;
            }
        }
    }

    e dirmi l'output che ottieni?
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  9. #9
    Ammazza andmin, ancora una volta hai dato prova di essere veramente un mito! Un incremento prestazionale sbalorditivo di almeno il 64%!!!

    andbin code : 486.2584456899999 millisecondi
    giannino code : 758.90362259 millisecondi


    complimenti! davvero bravo!
    Più pratica in futuro...

  10. #10
    Utente di HTML.it L'avatar di Alex'87
    Registrato dal
    Aug 2001
    residenza
    Verona
    Messaggi
    5,802
    Per curiosità l'ho provato anch'io

    andbin code : 66.25458868999998 millisecondi
    giannino code : 124.92250528999999 millisecondi

    Sulla mia macchina è più veloce ma la differenza tra i due è leggermente inferiore (+50% più o meno)
    SpringSource Certified Spring Professional | Pivotal Certified Enterprise Integration Specialist
    Di questo libro e degli altri (blog personale di recensioni libri) | ​NO M.P. TECNICI

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.