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

    [vb2008] velocizzare lettura files

    la prima volta che eseguo questa routine (nella cartella ci sono un migliaio di files di testo) dopo avere acceso il PC:

    codice:
    For Each foundFile As String In My.Computer.FileSystem.GetFiles( _
                Path, FileIO.SearchOption.SearchAllSubDirectories, "*.txt")
    
        Dim fs As FileStream = New FileStream(foundFile, FileMode.Open, _
                FileAccess.Read, FileShare.Read)
        Dim sr As StreamReader = New StreamReader(fs)
        FileReader = sr.ReadToEnd
        sr.Close()
        fs.Close()
    
       (Elaborazione FileReader, poca roba, meno di un millisecondo)
    
    Next
    ci metto quasi 30 secondi

    dalla seconda volta in poi, anche chiudendo il programma e riaprendolo, meno di un secondo!!

    Ora, dato che "every time you change a String variable, you leave the existing String object allocated and create a new one" evidentemente la prima volta alloca nuova memoria per ogni FileReader letto e dalla seconda volta in poi sa già dove trovare i dati in memoria, senza bisogno di rileggere i dati da file, velocizzando enormemente le operazioni.

    La cosa che trovo inspiegabile è che questa velocità 30 volte maggiore si realizza anche se chiudo e riapro il programma... comunque per carità, molto meglio così.

    La domanda che rimane a questo punto è: qualche idea per velocizzare le operazioni già alla prima volta??

    grz

  2. #2
    Utente di HTML.it L'avatar di ShaleN
    Registrato dal
    Aug 2010
    Messaggi
    517
    La cosa che trovo inspiegabile è che questa velocità 30 volte maggiore si realizza anche se chiudo e riapro il programma... comunque per carità, molto meglio così.
    Il motivo di questo l'ho letto su una discussione di qualche tempo fa. La prima volta che esegui un programma scritto con .Net Framework, questo viene tradotto dall' IL (intermediate linguage, ossia il linguaggio intermedio in cui viene compilato un sorgente .Net) in linguaggio macchina, e questa traduzione permane come cookie (spero che siano cookie, altrimenti MItaly mi squarta ) fino allo spegnimento del computer. Quindi, anche chiudendo il programma, non deve più essere effettuata la conversione e l'applicazione è più veloce.

    Per rendere il tutto più veloce da subito..... sorry, ma non ho idee
    Le vie del Signore sono infinite. È la segnaletica che lascia a desiderare.
    La luce viaggia più veloce del suono. Per questo alcune persone sembrano brillanti finchè non parlano.
    Occhio per occhio uguale... occhio al quadrato

  3. #3
    Utente di HTML.it
    Registrato dal
    Apr 2009
    Messaggi
    970

    Re: [vb2008] velocizzare lettura files

    Originariamente inviato da eziogsv

    La domanda che rimane a questo punto è: qualche idea per velocizzare le operazioni già alla prima volta??

    grz
    Si, scrivere un codice che sia più veloce nella ricerca e quello che hai utilizzato è il più lento. Oltretutto non ti permette neanche di gestire eventuali eccezioni che si verificano nell'accesso di cartelle e/o file interrompendo immediatamente il ciclo.
    Sbagliare è umano, perseverare è diabolico.

  4. #4
    Sei molto gentile nel suggerirmi di scrivere un codice più veloce... saresti stato ancor più gentile suggerendomi quale.

    inizialmente leggevo tramite un:
    codice:
    My.Computer.FileSystem.ReadAllText(....
    ma dopo aver letto

    http://msdn.microsoft.com/en-us/library/Aa289513

    che afferma che Sistem.IO è più efficente, sono passato a quello. Comunque tra i due c' è, alla prima lettura, una differenza irrisoria a favore di System.IO di pochi decimi di secondo su 30 secondi... evidentemente stai pensando ad altre soluzioni.

    Preciso a tuo rilievo che il ciclo è inserito in un Try... Catch con relativa completa gestione degli errori... non ho messo tutto il codice perché assolutamente ininfluente ai fini della domanda da me posta.

    Essendo files di testo potrei accedere direttamente con StreamReader, ma togliendo il codice relativco a FileStream non guadagno nulla (sempre pochi decimi di secondo su 30 secondi) e con Filestream posso prevedere uno Sharing raro ma non impossibile.

    Resto pertanto in speranzosa attesa di tuo PRATICO suggerimento su ulteriore codice più veloce nella lettura... grazie anticipatamente.

  5. #5
    Utente di HTML.it
    Registrato dal
    Apr 2009
    Messaggi
    970
    Originariamente inviato da eziogsv
    Sei molto gentile nel suggerirmi di scrivere un codice più veloce... saresti stato ancor più gentile suggerendomi quale.
    Come già suggerivo qual 3D fa questo codice, che utilizza una funzione ricorsiva e più efficiente del codice che hai scritto di circa il 20-25%.

    codice:
     Sub ListFiles(ByVal pattern As String, ByVal dir_info As DirectoryInfo)
            Try
                Dim info() As FileInfo = dir_info.GetFiles(pattern)
                For Each fs_info As FileInfo In info
                    Try
                        Dim fs As FileStream = New FileStream(fs_info.FullName, FileMode.Open, _
                          FileAccess.Read, FileShare.Read)
                        Dim sr As StreamReader = New StreamReader(fs)
                        FileReader = sr.ReadToEnd
                        sr.Close()
                        fs.Close()
                    Catch ex As Exception
                    End Try
    
                Next fs_info
                info = Nothing
    
                Dim subdirs() As DirectoryInfo = dir_info.GetDirectories()
                For Each subdir As DirectoryInfo In subdirs
                    ListFiles(pattern, subdir)
                Next subdir
            Catch ex As Exception
            End Try
        End Sub
    
     Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim s As New System.IO.DirectoryInfo("C:\Programmi")
            ListFiles("*.txt", s)     
        End Sub

    Preciso a tuo rilievo che il ciclo è inserito in un Try... Catch con relativa completa gestione degli errori... non ho messo tutto il codice perché assolutamente ininfluente ai fini della domanda da me posta.
    Assolutamente non va bene, se durante la lettura dei file nella funzione:

    codice:
    My.Computer.FileSystem.GetFiles....
    nel ciclo For...Each

    codice:
     For Each foundFile As String In My.Computer.FileSystem.GetFiles(.........)
                    
     Next
    si verificasse un'eccezione (esempio di accesso a una directory o file) puoi si gestire l'eccezione che si verifica con un blocco Try.....Catch ma purtroppo ti perdi i restanti file che la funzione doveva restituire.


    Sbagliare è umano, perseverare è diabolico.

  6. #6
    ho provato il tuo codice... inserendo uno StopWatch tarato in millisecondi sia per il mio che per il tuo.

    Che tu ci creda o no, alla prima lettura dopo l' accensione del PC:

    Mio codice: 33072
    Tuo codice: 33826

    Boh, dipenderà dal numero e dalla grandezza dei files... come detto i miei sono un migliaio di grandezza variabile tra i 4Kb ed i 600Kb, con grandezza media intorno ai 90 Kb.

    Il tuo codice si riprende dalla seconda lettura in poi:

    Mio codice: 747
    Tuo codice: 564

    Ma dalla seconda lettura in poi il programma diventa comunque accettabile, non sono 0.2 secondi a fare la differenza: è la prima lettura che è improponibile, miseria ladra.

    Evidentemente il primo passaggio degli StreamReader viene memorizzato nella cache e da li in poi l' accesso al disco diventa inesistente con conseguente velocità 60x... il lavoro di ottimizzazione pertanto più che nel "presentare sul vassoio" i files allo StreamReeder dovrebbe essere come far si che StreamReader IN SE' legga i files più velocemente...

    Nel frattempo ho provato un pout-purri di esempi trovati sul web, dalla lettura asincrona al ThreadPool... al primo passaggio le differenze sono inesistenti a fronte di un codice inutilmente più complesso e MOLTO più incline a generare eccezioni....
    .

  7. #7
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,465

    Re: [vb2008] velocizzare lettura files

    Originariamente inviato da eziogsv
    la prima volta che eseguo questa routine (nella cartella ci sono un migliaio di files di testo) dopo avere acceso il PC [...]
    ci metto quasi 30 secondi
    dalla seconda volta in poi, anche chiudendo il programma e riaprendolo, meno di un secondo!!
    Questo può essere dovuto a un minimo di cache che il sistema dedica ai file esterni.
    Tuttavia, sarebbe interessante sapere se 1) i file sono su unità locali oppure si trovano in rete, 2) quanti sono, 3) che dimensioni hanno nel complesso, 4) se è proprio necessario scandire anche le sottodirectory.

    Originariamente inviato da eziogsv
    Ora, dato che "every time you change a String variable, you leave the existing String object allocated and create a new one" evidentemente la prima volta alloca nuova memoria per ogni FileReader letto e dalla seconda volta in poi sa già dove trovare i dati in memoria, senza bisogno di rileggere i dati da file, velocizzando enormemente le operazioni.
    Dubito che questo fattore, che riguarda la gestione delle stringhe in quanto tale più che l'accesso a file esterni, abbia qualcosa a che fare con il problema.

    Originariamente inviato da eziogsv
    La cosa che trovo inspiegabile è che questa velocità 30 volte maggiore si realizza anche se chiudo e riapro il programma... comunque per carità, molto meglio così.
    Il che fa molto sospettare l'intervento di una cache esterna...

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  8. #8
    I files sono un migliaio, nel mio caso sono su HD interno (più precisamente su 2 HD in Raid1, quindi teoricamente la velocità di lettura dovrebbe essere un attimino maggiore), ed hanno una dimensione complessiva di 47.5 Mb.

    Ora, visto che oggi come oggi l' HD più scabeccio nei test reali legge sui 50 MB/s, non dico che mi aspetto di leggerli in 1 secondo, dato che sono 1.000 e vanno aperti e chiusi, ma certo la cosa non può richiedere più di 2-3 secondi e non i 30 secondi e più della prima volta che lancio il programma.

    Nel mio caso i files non sono in sottocartelle, ma dato che potrebbero esserlo il codice lo prevede, ma anche in questo caso mi aspetto un calo di prestazioni di qualche decimo di secondo, non di più.

    Preciso che se sostituisco: FileReader = sr.ReadToEnd

    con: FileReader = sr.ReadLine()

    cioè se leggo solo la prima riga anziché tutto il file non ho il minimo miglioramento in fatto di prestazioni al primo lancio del PC (siamo sempre sui 30 secondi)... e ciò mi convince che di quei 30 e passa secondi la maggior parte è dedicata ad organizzare una cache o un qualche buffer, destinati a durare finché non si chiude il PC.... E NON a leggere dati.

    Come già detto se chiudo il programma e lo rilancio i tempi diventano ridicoli, e se lancio il compilato invece che il debug anche esso si allaccia alla cache (non so proprio come, dal momento che a tutti gli effetti (vedi My.Settings ecc) dovrebbe essere un altro programma)... ed invece anche lui da subito legge il ciclo in meno di un secondo.

    Preciso altresì che se, come detto, all' avvio del PC leggo solo la prima riga, poi cambio il codice e rilancio, a questo punto per leggere tutto il testo non rioccorrono 30 secondi, ma 6 secondi: a mio parere questa è la prova definitiva che non è un problema di lettura FISICA su HD (che imho non dovrebbe richiedere più di un paio di secondi) ma di cache da organizzare da parte del codice.

    Quindi a questo punto la domanda è: come organizzare la cache / riservare memoria per i buffer tramite codice PRIMA di iniziare a leggere i dati?
    .

  9. #9
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,465
    Io darei un'occhiata anche alla presenza di possibili antivirus che potrebbero leggere preventivamente qualsiasi file a cui si accede...
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  10. #10
    Ho Nod32, ed i file con estensione .txt sono esclusi dal controllo.

    Comunque per prova ho disabiltato tutto e riavviato: primo lancio siamo sempre sui 30 secondi, dal secondo in poi meno di 1 secondo... stramalediz.....

    Ho anche provato a sostituire la variabile Stringa (ogni variazione del valore comporta la creazione di un nuovo oggetto) con uno StringBuilder, ma al primo lancio non ci sono incrementi misurabili di prestazioni.

    Se sostituisco FileReader = sr.ReadToEnd con FileReader = "WWW" il tempo di esecuzione non è misurabile da StopWatch ( mi da 0 millisecondi), quindi l' unico vero problema nasce non nella dichiarazione di FileStream e Stream reader, ma in questa unica riga di codice:

    FileReader = sr.ReadToEnd

    e visto che i tempi sono uguali a FileReader = sr.ReadLine(), cioè sia che leggo pochi Kb sia che leggo 47.5 MB continuo a pensare che questa è dimostrazione pratica che non è un problema di lettura FISICA di dati ma di organizzazione di un qualche cosa che ignoro (cache? buffer?) da parte del Reader

    Già, ma cosa e come organizzarlo meglio???
    .

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.