Async await

di il
31 risposte

Async await

Come molti di voi sanno, sto cercando di imparare il C#.
e mi esercito cercando problemi.
e stavolta ho trovato questo.

ho un file di testo e il mio scopo è creare un altro file di testo "filtrato" con le informazioni che mi interessano.

funziona tutto bene finche le righe sono poche.
ma con 500.000 righe come avvio la procedura si "ferma" tutto. non si blocca. Ma finché non finisce l'elaborazione non posso fare altro.

non ho ancora studiato la differenza tra THREAD e ASYNC.
ma visto che nel codice c'è ".ReadLineAsync" ho pensato di studiare prima ASYNC AWAIT.
namespace LeggiFileDiTesto
{
    public partial class frmProdotti : Form
    {
        public frmProdotti()
        {
            InitializeComponent();
        }
        
        
        string Linea;
        string[] subLinea;
        string percorsoFile;
        
        int subCampi;
        
        private void btnAvvia_Click(object sender, EventArgs e)
        {
            LeggiFileTxt();
        }



        private void LeggiFileTxt()
        {
            int i=0;
            openFile.ShowDialog();
            percorsoFile = openFile.FileName;
            bool continua = true;
            StreamReader LeggiTxt = new StreamReader(percorsoFile);
            while (continua)
            {
                i++;
                Linea =  LeggiTxt.ReadLine();
                lblRigoLetto.Text = Linea;
                subLinea = Linea.Split(';');
                subCampi = subLinea.Length;
                lbli.Text = i.ToString();
                //Application.DoEvents();

                if (i >= Convert.ToInt32(txtRigaNum.Text))          // serve per andare direttamente alla riga che ci interessa analizzare
                {
                    if (subCampi > 1)                               // questo controllo serve quando la riga non contiente prodotti  
                    {
                        if (subLinea[1] == txtProdotto.Text)          // serve per filtrare il prodotto
                        {
                            
                            
                            switch (subLinea[0])
                            {

                                case "0":
                                    //codice
                                    break;
                                case "1:
                                    //codice
                                    break;
                                case "2":
                                    //codice
				    break;
                                case "3":
                                    //codice
                                    break;
                                case "4":
                                    //codice
                                    break;
                                case "5":
                                    //codice
                                    break;
                            }
                        }
                    }
                }
                
                if (LeggiTxt.EndOfStream) continua = false;
            }
            LeggiTxt.Close();
           
        }
    }

}



Però anche aggiungendo async await nulla cambia. Funziona tutto ma finche non finisce di leggere il file non posso fare niente.

è lo stesso codice con l'aggiunta di async e await
namespace LeggiFileDiTesto
{
    public partial class frmProdotti : Form
    {
        public frmProdotti()
        {
            InitializeComponent();
        }
        
        
        string Linea;
        string[] subLinea;
        string percorsoFile;
        
        int subCampi;
        
        private void btnAvvia_Click(object sender, EventArgs e)
        {
            LeggiFileTxt();
        }



        private async void LeggiFileTxt()							// <-------------------------------------- async
        {
            int i=0;
            openFile.ShowDialog();
            percorsoFile = openFile.FileName;
            bool continua = true;
            StreamReader LeggiTxt = new StreamReader(percorsoFile);
            while (continua)
            {
                i++;
                Linea =  await LeggiTxt.ReadLineAsync();                              //<-------------------------------------- await + ReadLineAsync
                lblRigoLetto.Text = Linea;
                subLinea = Linea.Split(';');
                subCampi = subLinea.Length;
                lbli.Text = i.ToString();
                //Application.DoEvents();

                if (i >= Convert.ToInt32(txtRigaNum.Text))         
                {
                    if (subCampi > 1)                           
                    {
                        if (subLinea[1] == txtProdotto.Text)        
                        {
                            
                            
                            switch (subLinea[0])
                            {

                                case "0":
                                    //codice
                                    break;
                                case "1:
                                    //codice
                                    break;
                                case "2":
                                    //codice
				    break;
                                case "3":
                                    //codice
                                    break;
                                case "4":
                                    //codice
                                    break;
                                case "5":
                                    //codice
                                    break;
                            }
                        }
                    }
                }
                
                if (LeggiTxt.EndOfStream) continua = false;
            }
            LeggiTxt.Close();
           
        }
    }

}
Dove sbaglio?

Grazie

31 Risposte

  • Re: Async await

    Pivello ha scritto:


    Però anche aggiungendo async await nulla cambia. Funziona tutto ma finche non finisce di leggere il file non posso fare niente.
    [...]
    Dove sbaglio?
    Sembrerà una domanda scontata ma... hai letto come si usano e come funzionano le parole chiavi async e await?

    Oppure hai semplicemente sperato che usando un metodo con scritto "Async" in fondo e mettendoci un "Await" davanti tutto si risolvesse per magilla?
  • Re: Async await

    Ho finito adesso di studiare l esempio sul sito della Microsoft. E c hai ragione... volevo fare il mago
    Tanto lo sai che con me avete passato il guaio.

    Alla prossima.
  • Re: Async await

    Ma... imparare ad usare i metodi asincroni è sicuramente una delle cose che danno maggior soddisfazione nella programmazione in C#

    Ma molto più importante di fare una cosa lenta in un thread separto, è fare la stessa cosa velocemente, e il thread separato potrebbe non servire più.

    Nel tuo caso leggi il file a righe e ogni riga esegui delle operazioni.
    invece di usare:
    
            StreamReader LeggiTxt = new StreamReader(percorsoFile);
                while (continua)
                {
                    i++;
                    Linea =  LeggiTxt.ReadLine();
                    lblRigoLetto.Text = Linea;
                    subLinea = Linea.Split(';');
                    //--------------
                    //--------------
    
    Metti in un colpo solo tutto il file in una lista, e poi esegui le operazioni sulla lista, la velocità si incrementerà di migliaia di volte.
    per dichiarare una lista di nome TESTOletto:
    
    private List<string> TESTOletto = new List<string>();
    
    per caricare nella lista un file testo in un colpo solo:
    
    TESTOletto = File.ReadAllLines(percorsoFile).ToList(); // legge il file testo
    
    ora puoi lavorare riga per riga il testo che è in ram, ogni riga ha il suo indice, esempio la riga zero: TESTOletto[0];
    Hai tutte le proprietà:
    TESTOletto.Count() ti dice quante righe hai letto
    TESTOletto[20].Contains("ciao") ti dice se la stringa è presente
    guardale con l'intellisense, c'è tutto quello che ti serve.

    poi con backgroundworker o simili, migliori ulteriormente.

    Quello che non si può migliorare è la visualizzazione in un colpo solo di testi grandi in un controllo, tipo RichTextBox o ListBox, perché mentre il controllo carica il testo il form sarà irrimediabilmente bloccato.

    In questi casi invece di caricare 500.000 righe di testo nel controllo, si caricano solo le righe effettivamente visualizzate, scorrendo la lista TESTOletto in accordo con una scrollbar, ma questa è un'altra storia.
  • Re: Async await

    Rubik ... mi sfugge cosa c'entri il tuo post con l'async await...
  • Re: Async await

    Rubik ha scritto:


    Metti in un colpo solo tutto il file in una lista, e poi esegui le operazioni sulla lista, la velocità si incrementerà di migliaia di volte.
    Diciamo che questo suggerimento, se applicato su scala globale, non è molto corretto: se ho un file che varia da 500MB a 1GB e oltre in termini di dimensioni, caricando tutte le righe il programma va in OutOfMemory e il gioco è finito.

    Ammesso che ci riesca, nella fase di caricamento il tempo dipende sostanzialmente dalle dimensioni del file, e per quel tempo il programma rimane comunque bloccato, quindi a che pro?

    In realtà, se non c'è bisogno di trattare le righe in modo aggregato, meglio caricare riga per riga: le tempistiche sono comparabili e comunque si ha rispetto della RAM e del fatto che, oltre al nostro programma, sulla macchina ipoteticamente girano anche altre applicazioni e servizi che hanno diritto al loro spazio.

    L'unica questione è usare correttamente gli strumenti che il framework mette a disposizione per evitare al programma di apparire come bloccato, che nel caso in esame è solo una questione legata a una migliore "user experience" (UX).

    Ciao!
  • Re: Async await

    oregon ha scritto:


    Rubik ... mi sfugge cosa c'entri il tuo post con l'async await...
    L'ho scritto in premessa, se hai un codice che per essere eseguito impiega 10 secondi, ma se scritto in modo diverso impiega 0.5 secondi; invece di cercare di eseguire i 10 secondi in background, è meglio eseguire i 0.5 secondi su singolo thread. Poi se anche i 0.5 secondi li esegui in background tanto meglio.
  • Re: Async await

    Rubik ha scritto:


    se hai un codice che per essere eseguito impiega 10 secondi, ma se scritto in modo diverso impiega 0.5 secondi [...]
    Ovvio, però nello scenario che stiamo guardando, la differenza di tempo nella lettura di un file riga per riga o come tutt'uno non è così elevata.
    Certo, a meno che tu non stia lavorando con un disco che abbia dei seri problemi hardware.
  • Re: Async await

    Alka ha scritto:


    Rubik ha scritto:


    Metti in un colpo solo tutto il file in una lista, e poi esegui le operazioni sulla lista, la velocità si incrementerà di migliaia di volte.
    Diciamo che questo suggerimento, se applicato su scala globale, non è molto corretto: se ho un file che varia da 500MB a 1GB e oltre in termini di dimensioni, caricando tutte le righe il programma va in OutOfMemory e il gioco è finito.

    Ammesso che ci riesca, nella fase di caricamento il tempo dipende sostanzialmente dalle dimensioni del file, e per quel tempo il programma rimane comunque bloccato, quindi a che pro?

    In realtà, se non c'è bisogno di trattare le righe in modo aggregato, meglio caricare riga per riga: le tempistiche sono comparabili e comunque si ha rispetto della RAM e del fatto che, oltre al nostro programma, sulla macchina ipoteticamente girano anche altre applicazioni e servizi che hanno diritto al loro spazio.

    L'unica questione è usare correttamente gli strumenti che il framework mette a disposizione per evitare al programma di apparire come bloccato, che nel caso in esame è solo una questione legata a una migliore "user experience" (UX).

    Ciao!
    Vero, non può essere generalizzato, per la mia esperienza operare in questo modo è conveniente per testi che pesano fino a 100/200MB, l'incremento di prestazioni tra operare single line e in blocco, è di circa 1000 volte sul caricamento, e 20 volte sulle operazioni di ricerca e splittaggio righe ecc ecc con il testo direttamente in ram.
  • Re: Async await

    Per me ogni risposta che mi date è importante.
    Anche quella di Rubik.
    Mi aiutate a capire come posso fare diversamente.
    Faccio un lavoro che non centra niente con la programmazione e l'informatica. L'età e il tempo che riesco a "rubare" non mi aiutano.
    E voi siete l'unico "confronto/riscontro" che ho.
    E grazie soprattutto a voi posso fare esperienza.
    Sono i vostri input che mi danno la voglia di cercare altro.
    Ogni vostra risposta la conservo gelosamente. E all'occorrenza vado a rileggerla.
    E adesso smetto, prima che Alka mi cazzea

    GRAZIE... sempre GRAZIE a TUTTI.
  • Re: Async await

    Rubik ha scritto:


    ...
    Sono d'accordo con Alka ... la questione di leggere il file tutto in un colpo o meno non mi pare c'entri moltissimo con la discussione. La questione specifica dipende da quanto è grande il file e quanta RAM fisica hai (e tante altre amenità). Se il file è grande o la RAM disponibile non molta, fai frullare il disco in modo che tutto diventerà ancora più lento. Consiglio di cominciare a leggere qualcosa a partire da

    https://docs.microsoft.com/it-it/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model
  • Re: Async await

    Grazie per avermi messo il dubbio ho scritto un codice al volo e se si usa streamreader, la velocità di caricamento non cambia. Sono della vecchia scuola e le differenze notevoli c'erano con la vecchia open un migliaio di volte più lenta.

    progetto console C#:
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.IO;
    using System.Diagnostics;
    
    
    namespace TestiGrandiConsole
    {
        class Program
        {
            static Stopwatch StWa = new Stopwatch();
            static void Main(string[] args)
            {
                List<string> TESTOletto = new List<string>();
                UInt32 Quante = 1000000;
                //**** CREA UN FILE TESTO DA UN MILIONE DI RIGHE ****
                string[] UnMilione = new string[Quante];
                string NomeFile = "UnMilioneDiRighe.txt";
                StWa.Reset(); // azzera il tempo
                AggiornaConsole(" Genero " + Quante.ToString("#,#") + " di righe");
                for (UInt32 i = 0; i < Quante; i++)
                {
                    UnMilione[i] = "Riga N." + (i + 1).ToString("0000000") + " - Testo di grandi dimensioni, per verifica velocità di caricamento e visualizzazione, creato in modo fittizio ed automatizzato.";
                }
                AggiornaConsole(" file testo con " + Quante.ToString("#,#") + " righe, generato");
                File.WriteAllLines(NomeFile, UnMilione); // Salva matrice di stringhe
                AggiornaConsole(" file testo con " + Quante.ToString("#,#") + " righe, salvato");
                AggiornaConsole(" inizio caricamento file testo in blocco");
                TESTOletto = File.ReadAllLines(NomeFile).ToList(); // Carica in lista
                AggiornaConsole(" file testo con " + TESTOletto.Count.ToString("#,#") + " righe, caricato");
                TESTOletto.Clear();
                AggiornaConsole(" inizio caricamento file testo riga riga");
                StreamReader LeggiTxt = new StreamReader(NomeFile);
                while (!LeggiTxt.EndOfStream)
                {
                    TESTOletto.Add(LeggiTxt.ReadLine()); // Carica in lista
                }
                LeggiTxt.Close();
                AggiornaConsole(" file testo con " + TESTOletto.Count.ToString("#,#") + " righe, caricato");
                Console.Write("premi un tasto per uscire");
                int tasto = Console.Read();
            }
    
            static void AggiornaConsole(string Log)
            {
                //**** VISUALIZZA TEMPI E INFO ****
                Console.WriteLine(DateTime.Now + " +" + StWa.ElapsedMilliseconds.ToString("0000") + " ms. [" + Log + " ]");
                StWa.Reset();
                StWa.Start();
            }
        }
    }
    
  • Re: Async await

    Rubik ha scritto:


    Grazie per avermi messo il dubbio ho scritto un codice al volo e se si usa streamreader, la velocità di caricamento non cambia, sono della vecchia scuola e le differenze notevoli c'erano con la vecchia open un migliaio di volte più lenta.
    Eseguendo il tuo codice, ho ottenuto questo risultato:
    
    27/11/2020 20:18:31 +0 ms. [ Genero 1000000 di righe ]
    27/11/2020 20:18:32 +940 ms. [ file testo con 1.000.000 righe, generato ]
    27/11/2020 20:18:33 +437 ms. [ file testo con 1.000.000 righe, salvato ]
    27/11/2020 20:18:33 +0 ms. [ inizio caricamento file testo in blocco ]
    27/11/2020 20:18:34 +1041 ms. [ file testo con 1.000.000 righe, caricato ]
    27/11/2020 20:18:34 +1 ms. [ inizio caricamento file testo riga riga ]
    27/11/2020 20:18:35 +1193 ms. [ file testo con 1.000.000 righe, caricato ]
    premi un tasto per uscire
    
    Come vedi, le tempistiche sono perfettamente comparabili: 1.041ms per la lettura in blocco, 1.193ms per la lettura riga per riga.

    Tra l'altro, bisogna tenere presente che .NET è un runtime non deterministico: il risultato può variare da esecuzione a esecuzione, e in alcuni casi può essere influenzato dal momento in cui il Garbage Collector decide di intervenire, quindi di fatto si può concludere che il tempo richiesto dalle due operazioni è lo stesso.

    Ciao!
  • Re: Async await

    Alka ha scritto:


    Eseguendo il tuo codice, ho ottenuto questo risultato:
    
    27/11/2020 20:18:31 +0 ms. [ Genero 1000000 di righe ]
    27/11/2020 20:18:32 +940 ms. [ file testo con 1.000.000 righe, generato ]
    27/11/2020 20:18:33 +437 ms. [ file testo con 1.000.000 righe, salvato ]
    27/11/2020 20:18:33 +0 ms. [ inizio caricamento file testo in blocco ]
    27/11/2020 20:18:34 +1041 ms. [ file testo con 1.000.000 righe, caricato ]
    27/11/2020 20:18:34 +1 ms. [ inizio caricamento file testo riga riga ]
    27/11/2020 20:18:35 +1193 ms. [ file testo con 1.000.000 righe, caricato ]
    premi un tasto per uscire
    
    Come vedi, le tempistiche sono perfettamente comparabili: 1.041ms per la lettura in blocco, 1.193ms per la lettura riga per riga.
    non pensavo che avresti pubblicato il test, che figura ci faccio tutto disallineato un milione all'inizio è senza punti poi con i punti...
    l'ho corretto e messo il nuovo codice nel post precedente. Il mio risultato:
    
    27/11/2020 23:13:56 +0000 ms. [ Genero 1.000.000 di righe ]
    27/11/2020 23:13:57 +1231 ms. [ file testo con 1.000.000 righe, generato ]
    27/11/2020 23:13:58 +0577 ms. [ file testo con 1.000.000 righe, salvato ]
    27/11/2020 23:13:58 +0000 ms. [ inizio caricamento file testo in blocco ]
    27/11/2020 23:13:59 +1492 ms. [ file testo con 1.000.000 righe, caricato ]
    27/11/2020 23:13:59 +0002 ms. [ inizio caricamento file testo riga riga ]
    27/11/2020 23:14:01 +1616 ms. [ file testo con 1.000.000 righe, caricato ]
    premi un tasto per uscire
    
  • Re: Async await

    Rubik ha scritto:


    che figura ci faccio tutto disallineato [...]
    
    27/11/2020 23:13:59 +1492 ms. [ file testo con 1.000.000 righe, caricato ]
    27/11/2020 23:14:01 +1616 ms. [ file testo con 1.000.000 righe, caricato ]
    
    A me pare che invece tu sia allineato: le tue tempistiche, anche se leggermente superiori in entrambi i casi (ma questo dipende da CPU, RAM, ecc. del tuo PC rispetto alla dotazione del mio), come vedi mantengono comunque una differenza comparabile di circa 150 millisecondi, più facilmente dovute a interventi del GC che non ad altro.

    Comunque siamo abbondantemente OT.
Devi accedere o registrarti per scrivere nel forum
31 risposte