Domanda rapida: c'è qualche ovvio vantaggio nell'usare la comunicazione asincrona con la classe NetworkStream (generata da TcpClient), cioè i metodi BeginRead/BeginWrite invece di eseguire un thread separato e utilizzare operazioni sincrone su tale , cioè leggi/scrivi? La mia impressione è stata (potrebbe facilmente essere del tutto sbagliato) che le operazioni asincrone siano non bloccanti ed eseguite a livello di sistema operativo (nello stack TCP, forse?), Con un item del pool di thread per il callback. Sto pensando che sicuramente deve essere diverso dal chiamare ThreadPool.QueueUserWorkItem sul metodo sincrono, o ci sarebbe un piccolo punto nel fornirlo. Ora, sono abbastanza fiducioso che questo è il genere di cose (chiamate a livello di sistema operativo) che si verificano almeno per l'I/O dei file, ma se qualcuno potrebbe chiarire la questione sulla comunicazione di rete (TCP), sarebbe molto utile. Fondamentalmente, vorrei sapere se c'è qualche vantaggio specifico per entrambi i metodi (oltre a quello ovvio di essere in grado di utilizzare le classi BinaryReader/StreamReader con le chiamate sincrone).Comunicazione TCP asincrona in .NET
risposta
C'è una differenza, se si utilizza un thread di lavoro per chiamare la versione sincrona si legherà uno dei thread su una chiamata di blocco.
Considerando che i metodi Begin non legheranno un thread ma utilizzeranno invece un callback su un segnale I/O appropriato, la richiamata verrà quindi eseguita su un thread dal pool.
Come altri hanno sottolineato, l'allocazione di un altro thread al processo avrà un impatto quando si utilizza il metodo sincrono man mano che si aumenta il numero di connessioni simultanee.
Tuttavia, se sai che avrai solo un numero limitato di connessioni, direi che diventa un lavaggio e dovresti scegliere il metodo più naturale per la tua applicazione.
Nel caso in cui il thread overhead sia trascurabile, mi aspetto che i due scenari si presentino in questo modo.
asincrono:
- Fate chiamata a BeginRead/BeginWrite
- "Il sistema" (quadro/OS) è informato di ciò che si vuole
- lettura/scrittura completa
- " Il sistema "indica una discussione nel pool di thread per richiamare la richiamata
- Fare tutto ciò che è necessario per completare l'operazione
sincrono in un altro thread:
- si ottiene un thread dal pool di thread per gestire l'IO
- Fate chiamata alla lettura/scrittura
- "Il sistema" (quadro/OS) viene informato di ciò che si desidera
- Lettura/Scrittura completata
- Fare tutto ciò che è necessario fare per completare l'operazione
L'unica differenza qui è che il passaggio 4 dalla chiamata asincrona diventa il passaggio 1 nel sincrono in un altro caso di thread.
Sì, questa era fondamentalmente la mia altra considerazione. Hmmmm, ora ho le stesse due viste opposte con le quali ho iniziato ... – Noldorin
Un thread, anche se bloccato, è una parte significativa della risorsa (a partire da 1 MB di spazio di stack assegnato dallo spazio della VM del processo). – Richard
Lo comprerò in una certa misura, ma visto che stiamo parlando di prendere una discussione dalla piscina qui, non so che importi molto. La mia inclinazione sarebbe quella di fare qualsiasi cosa sia più naturale per l'applicazione a meno che non riesca a dimostrare che ho avuto un problema. Ottimizzazione prematura e tutto ... –
Sono d'accordo con AnthonyWJones, immagina che il tuo pool di thread abbia 10 thread, ma hai 100 client abbastanza passivi. Con le chiamate asincrone puoi iniziare BeginRead per ognuna di esse e, quando i dati di qualcuno sono pronti, verranno elaborati da uno dei thread del pool. Ma se tenterai di utilizzare QueueUserWorkItem, pianifichi la ricezione dei dati da soli 10 client. E se non inviano nulla in un'ora, altri 90 clienti non avranno mai la possibilità di ottenere dati.
Infatti, vedo che chiamare il metodo Begin chiaramente non è equivalente a QueueUserItmem ora ... Tuttavia, il punto principale è come si confronta con l'esecuzione di un thread separato con operazioni sincrone. – Noldorin
Non c'è alcuna differenza se si utilizza in modo esplicito thread da un pool o se si crea un numero di thread da soli - in qualsiasi modo si è limitato nel numero di thread ... Con le operazioni asincrone, i thread vengono utilizzati solo per fare il vero lavoro, e poi rilasciato. Con Sync ops i thread possono essere bloccati solo da attesa in attesa. – alex2k8
Ok, questo ha senso ora. Grazie per le spiegazioni. – Noldorin
Non sono proprio sicuro del motivo per cui NetworkStream ha persino un BeginRead/Write, poiché questo in pratica viola lo scopo di NetworkStream in primo luogo. Utilizzando i metodi Async, si ottiene una risposta più rapida, una maggiore scalabilità e un ridotto consumo di risorse.
Se si ha solo una connessione alla volta, non importa molto se si utilizza un thread pool o meno, ma se si accettano molte connessioni, si consiglia di utilizzare async.
Capisco cosa intendi. Questi metodi asincroni sarebbero probabilmente più adatti all'interno della classe TcpClient. Sembra che il consenso si stia leggermente orientando verso l'utilizzo dei metodi asincroni per prestazioni migliori (se non marginalmente). – Noldorin
Giusto, questo è esattamente ciò che sospettavo. Quindi si consiglia di utilizzare i metodi Begin piuttosto che i metodi sincroni su un thread separato, dove possibile? Sembrerebbe più elegante, se non più efficiente, farlo in questo modo. – Noldorin
L'implementazione di framework .NET di pattern di livello basso (BeingXX/EndXX) generalmente utilizza porte di completamento IO. Questo è l'approccio IO scalabile disponibile sotto Windows. – Richard
@Noldorin: Sì, suggerirei di utilizzare i metodi Begin principalmente perché il codice è più semplice in questo modo, fortunatamente in questo caso l'approccio più semplice è anche più efficiente. – AnthonyWJones