Operazioni su stringa molto lente

di il
7 risposte

Operazioni su stringa molto lente

Ciao a tutti, sono alle prese con una cosa alquanto strana, e sono riuscito a fare qualche riga di codice che mostra il problema, e riassumendo succede che:

se scarico tramite WebClient una certa stringa da internet tutte le operazioni seguenti relative a questa stringa sono rallentate tantissimo, facendo il debug riga per riga, anche un semplice Substring, IndexOf, ToUpper eccetera ci mette un sacco di tempo.

Penso che il motivo sia perchè all'interno di questa stringa ci siano dei caratteri non validi o decodifiche diverse, ma non saprei come identificarle.

Se provate il codice seguente vedrete che per scrivere questa stringa su di un file ci mette qualche secondo (tempo 1), mentre per scrivere una stringa della stessa lunghezza ci mette pochi millisecondi (tempo 2)
Ho provato a cambiare il Encoding.UTF8 con Encoding.Default ma non è cambiato nulla

Qualche idea ??
Grazie mille
Sergio
        Dim wc As New System.Net.WebClient
        wc.Encoding = System.Text.Encoding.UTF8
        wc.Headers(HttpRequestHeader.UserAgent) = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"

        Dim page1 = wc.DownloadString("https://www.amazon.it/Ferrino-Zaino-TRANSALP-60-Colore/dp/B07JL3SWR5/ref=sr_1_1?__mk_it_IT=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=8014044953729&qid=1597399629&sr=8-1")

        ' scrivo il risultato su un file, e calcolo quanto ci metto
        Dim sw = Stopwatch.StartNew
        My.Computer.FileSystem.WriteAllText(My.Computer.FileSystem.SpecialDirectories.Desktop & "\MioFile1.txt", page1, False)
        sw.Stop()
        MsgBox("Tempo 1: " & sw.ElapsedMilliseconds & " ms")

        ' ricreo una stringa lunga esattamente come la precedente
        Dim page2 = New String("X"c, page1.Length)
        ' ri-scrivo il risultato su un file, e calcolo quanto ci metto
        sw = Stopwatch.StartNew
        My.Computer.FileSystem.WriteAllText(My.Computer.FileSystem.SpecialDirectories.Desktop & "\MioFile2.txt", page2, False)
        sw.Stop()
        MsgBox("Tempo 2: " & sw.ElapsedMilliseconds & " ms")

7 Risposte

  • Re: Operazioni su stringa molto lente

    SirJo ha scritto:


    se scarico tramite WebClient una certa stringa da internet tutte le operazioni seguenti relative a questa stringa sono rallentate tantissimo, facendo il debug riga per riga, anche un semplice Substring, IndexOf, ToUpper eccetera ci mette un sacco di tempo.
    Occorre partire da uno dei capisaldi di .NET relativo alle stringhe che deve essere molto chiaro a qualsiasi sviluppatore: le stringhe sono immutabili.

    Questo significa che quando usi metodi tipo Substring() o similari, o più in generale quando usi metodi che vanno a trasformare la stringa originale in qualcosa di diverso (es. estraggono un pezzo, convertono in maiuscolo, minuscolo, accodano testo, ecc.), quello che materialmente avviene è la creazione di nuovi oggetti che contengono la stringa modificata, e che si affiancano ai precedenti, ammesso che qualcuna di esse non possa essere deallocata dal Garbage Collector se non più utilizzata.

    Se devi quindi lavorare con un testo all'interno di un ciclo, o fare operazioni ripetute che estrapolano modifiche da una stringa, è conveniente prediligere l'uso della classe StringBuilder, che nasce appositamente con lo scopo di affiancare il programmatore nella creazione e anche manipolazione (un po' più limitata) di una stringa agendo internamente sul buffer di memoria che ne contiene i caratteri, producendo una unica istanza di tipo String quando si invoca ad esempio il metodo ToString().

    Oltre a questo, nel tuo codice tu vai a salvare il testo su disco: il salvataggio deve tenere conto dell'encoding utilizzato e pertanto ciascun carattere della stringa deve essere trasformato nella sequenza di byte che lo rappresentano all'interno del file, e ciò avviene in modo diverso in base all'encoding scelto.

    Questo significa che salvare una sequela di "X" è diverso da salvare un testo dove vi sono caratteri misti, alcuni dei quali - prendendo come esempio l'encoding UTF8 - richiedono solo un byte, altri magari due, altri ancora addirittura quattro, a seconda del contenuto della stringa.

    E' pacifico che questo genere di operazione aumenta i tempi di salvataggio che saranno più o meno variabili in base alla probabilità che siano presenti caratteri di diverse famiglie piuttosto che si tratti in realtà di un solo carattere.

    Come ricerca ulteriore, suggerirei di leggere questo articolo sulla storia di Unicode e di approfondire i principi di funzionamento degli standard di trasformazione (UTF-x).

    Ciao!
  • Re: Operazioni su stringa molto lente

    Grazie della risposta, anche se (purtroppo) non c'entra nulla.

    Conosco bene il StringBuilder, ma come vedi nell'esempio che ho postato sulla stringa non ci faccio nessuna modifica, eppure il tempo per salvare circa 1,5 mbyte è altissimo.
    Se modifico la riga
    Dim page2 = New String("X"c, page1.Length)
    e al posto della "X" ci metto un carattere unicode (cioè che ha bisogno più di un byte per essere codificato) il risultato non cambia.

    Ho provato anche a fare un DownloadData (anzichè un DownloadString) in modo da escludere la codifica dei caratteri e poi scriverlo sul disco con WriteAllByte ma il risultato non cambia
  • Re: Operazioni su stringa molto lente

    SirJo ha scritto:


    Conosco bene il StringBuilder, ma come vedi nell'esempio che ho postato sulla stringa non ci faccio nessuna modifica
    Hai parlato tu di Substring() e IndexOf(), quindi ho dato per scontato che facessi operazioni di questo tipo senza aver riportato il codice relativo.

    SirJo ha scritto:


    Se modifico la riga
    Dim page2 = New String("X"c, page1.Length)
    e al posto della "X" ci metto un carattere unicode (cioè che ha bisogno più di un byte per essere codificato) il risultato non cambia.
    Anche in quel caso, il numero di byte è maggiore ma è sempre fisso, quindi questo potrebbe portare a coincidere con le dimensioni di qualche buffer che in questo modo ottimizza la scrittura di output.

    SirJo ha scritto:


    Ho provato anche a fare un DownloadData (anzichè un DownloadString) in modo da escludere la codifica dei caratteri e poi scriverlo sul disco con WriteAllByte ma il risultato non cambia
    Però se ripeti magari la scrittura della stringa scaricata di nuovo, in fondo alla procedura e dopo il resto, questa avviene in tempi molto più rapidi?
    Se sì, vuol dire che internamente vi sono delle ottimizzazioni di qualche tipo (es. buffer da predisporre nella fase iniziale della scrittura) che incidono sulla prima "write" ma che poi non ostacolano quelle seguenti, e magari il fatto che si verifichi proprio sulla stringa scaricata è puramente un caso.
  • Re: Operazioni su stringa molto lente

    X SirJo : per fare dei test sull'applicazione dovresti eseguirla non in debug,può darsi che ci sia differenza,ciao
  • Re: Operazioni su stringa molto lente

    Sul mio pc la differenza è solo di qualche decina di ms;
    ... non è che dipende dall'antivirus
  • Re: Operazioni su stringa molto lente

    sspintux ha scritto:


    Sul mio pc la differenza è solo di qualche decina di ms;
    ... non è che dipende dall'antivirus
    molto interessante, grazie per aver provato

    appena posso lo provo su di un altro PC, grazie mille

    EDIT:
    provato, la differenza è proprio minima

    ora resta il dubbio del perchè, ma quello che è assurdo, a parte il tempo esagerato della scrittura sul file, è tutta l'esecuzione del programma in debug (riga per riga) che ci mette 2-3 secondi ad ogni riga sebbene non stia modificando la stringa (come aveva supposto Alka)

    L'antivirus è il classico Windows Defender di Windows 10, non mi ha mai dato problemi in tutti questi anni, boh proverò a vedere, se avete idee di cosa devo controllare sono ben accette

    Grazie
    Sergio
  • Re: Operazioni su stringa molto lente

    Ho provato anch'io per curiosità e perché volevo verificare il funzionamento della classe Stopwatch.
    I risultati sono un po' random, ma in effetti la prima scrittura ci mette di solito di più (quasi il doppio) ma si tratta di 12-16 millisecondi contro i 7-8, su disco SSD.
    1) se sospetti che sia l'antivirus hai provato a disattivarlo? Non so se Win Defender lo permette, io uso l'avast e quando utilizzo Visual Studio lo disabilito perché altrimenti ad ogni debug rifa il controllo dell'eseguibile;
    2) non è che per caso ti stia partendo il disco? Provato a vedere i parametri smart ad esempio con CrystalDiskInfo?
    Lucius.
Devi accedere o registrarti per scrivere nel forum
7 risposte