Esiste un codice asincrono troppo elevato?

6

Al momento sono in giro con clienti e server in C # winform e sto provando a implementarlo in modo asincrono. Tuttavia, sto cominciando a chiedermi, dovrei usare il codice asincrono per tutto?

Ecco un elenco di ciò che sto facendo in modo asincrono al momento:

  1. TcpClient.BeginConnect con TcpClient.EndConnect

  2. NetworkStream.BeginRead with NetworkStream.EndRead

  3. TcpListener.BeginAcceptTcpClient con TcpListener.EndAcceptTcpClient

  4. Ascolto del thread sul server per le connessioni client

  5. Ascolto del thread sul client per i dati in arrivo dal server

  6. Attività di ascolto sul server per i dati in arrivo da ciascun client

  7. Nuova attività creata ogni volta che viene sollevato un evento come ConnectionLost (quindi il modulo corrispondente può essere aggiornato). Pensa a Delegate.BeginInvoke.

Tutto è configurato in modo asincrono e funziona bene, ma sto cominciando a chiedermi se tutti questi dovrebbero essere asincroni. Voglio dire, suona tutto bene e la gente afferma che sia efficiente a causa delle porte di completamento dell'IO che non bloccano o qualcosa del genere, ma è davvero?

Posso capire di avere un singolo thread per ascoltare sia sul client che sul server, e anche per leggerlo ha senso. Ma ogni volta che viene sollevato un evento (che può essere abbastanza spesso!), La sua invocazione dovrebbe essere davvero asincrona? Sembra che sto utilizzando Attività per tutto ciò che può essere reso asincrono e non sono sicuro che sia la migliore pratica.

    
posta user35028 26.09.2011 - 22:51
fonte

2 risposte

7

Sì, è davvero più efficiente fare tutte queste cose in modo asincrono. Se lo fai in modo sincrono, stai costantemente votando, il che spreca risorse e può farti perdere eventi se non li elabori abbastanza velocemente.

Inoltre, se provassi a fare tutte queste cose in modo sincrono, ti ritroverai impantanato in problemi di sincronizzazione stupidi, cercando di mescolare priorità, casi di bordo strani che si verificano quando un client prova a connettersi entro 22 msec da un altro client scollegamento, ma solo il giovedì quando c'è la luna piena.

Con il tuo progetto attuale, ogni attività separabile logicamente è separata dal resto del programma. È probabile che sia più facile scrivere e sarà molto più facile eseguire il debug se qualcosa va storto. Anche la manutenzione è più facile, perché è impossibile (ok, molto difficile) confondersi e modificare la cosa sbagliata. Avendo lavorato su sistemi come questo che non erano asincroni, posso attestare che è incredibilmente facile pensare che stai manipolando il buffer di input quando in realtà stai maneggiando il buffer di output.

Per quanto riguarda la tua domanda finale: sì, davvero dovresti aumentare ogni evento in modo asincrono. Rispondere a un evento può richiedere un lasso di tempo arbitrariamente lungo. Se lo scrivi in modo che la risposta all'evento venga eseguita in modo sincrono e tale risposta richieda molto tempo (che, in un'applicazione di comunicazione come questa, potrebbe essere di cinque secondi o meno), perderai gli eventi.

Il modello asincrono che stai utilizzando è molto simile a una coda implicita. Può tollerare picchi di traffico che potrebbero sopraffare un sistema sincrono. Finché, in media , puoi elaborare il traffico più velocemente di quanto non sia, sei a posto. Con un sistema sincrono, troppi segnali contemporaneamente o troppi segnali che impiegano molto tempo per essere elaborati, uccideranno l'applicazione. Con il modello asincrono, l'unico modo per uccidere l'applicazione è di sovraccaricare la coda.

    
risposta data 27.09.2011 - 00:27
fonte
0

Dalla domanda, sembra che tu abbia delle preoccupazioni circa le prestazioni delle operazioni asincrone in determinate circostanze. Le operazioni asincrone sono incredibilmente veloci ed efficienti perché sotto le copertine .NET utilizza i pool di thread: i thread per eseguire il codice esistono già e quindi non c'è praticamente alcuna penalità per selezionare uno di questi ed eseguire del codice su di esso.

Mentre d'altra parte, i guadagni in termini di prestazioni per async sono enormi. I metodi sincroni siederanno su un thread in attesa che alcune operazioni di I / O vengano completate come una lettura del disco o una chiamata di rete. Poiché le operazioni di I / O in genere richiedono molto più tempo per essere completate rispetto al calcolo effettivo della CPU, tale thread non sta facendo nulla per la sua intera esistenza. Questo è male per due ragioni. I thread in genere costano circa 1 MB di memoria e quando ci sono molti thread che bloccano tutte le operazioni di I / O a esecuzione prolungata, si ottiene un sacco di costosi cambiamenti di contesto mentre i thread vengono scambiati dentro e fuori dalla CPU.

Il risultato è che non ci sono praticamente mai problemi di prestazioni dall'uso di metodi asincroni. L'unico lato negativo è l'aumento della complessità del codice, ma il pattern C # async / await che arriva in C # 5.0 (collegato in precedenza) sembra che eliminerà sostanzialmente il problema tipicamente associato ad asincrona.

    
risposta data 27.09.2011 - 01:26
fonte

Leggi altre domande sui tag