2011-01-11 11 views
7

È OK eseguire un'elaborazione pesante nei callback asincroni di .NET, eseguendoli per più secondi prima di tornare? O sto privando il sistema operativo/il runtime di risorse importanti?OK per eseguire l'elaborazione pesante nei callback asincroni?

Ad esempio, considerare TcpListener.BeginAcceptSocket. La mia callback inizia invocando EndAcceptSocket, quindi impiega un po 'di tempo a ricevere dati e solo dopo chiude il socket e ritorna. È così che doveva essere usato, o mi aspetto che esegua l'elaborazione extra sul mio thread?

+0

io vi invito a dare un'occhiata a Rx (estensioni reattivi) che rende la programmazione asincrona una bella passeggiata serale in un parco! http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx – gideon

+0

Alcuni utili collegamenti Rx: http://rxwiki.wikidot.com/ Ecco un piccolo codice che ho scritto per aggiornare in modo asincrono una casella di riepilogo ogni volta che digito in una casella di testo e limitarla di 0,5 secondi. Vedi-> http://stackoverflow.com/questions/4655619/simple-rx-code-silently-fails-in-windows-forms-only-during-debugging-in-visual-st – gideon

risposta

1

Sì, questo è il modo in cui i socket asincroni (client Tcp, listener, ecc.) Sono progettati per l'uso. Dovresti sempre assicurarti di invocare il metodo aysnc di fine e quindi eseguire qualsiasi elaborazione desideri. Non invocando i metodi EndAccept(), EndSEnd(), EndReceive(), ecc., Ti lascia potenzialmente aperto a una perdita di memoria, quindi è sempre una buona pratica da seguire.

I thread utilizzati non sono diversi rispetto a se si fosse effettuato manualmente lo spooling di un thread in background, e sono infatti progettati per essere utilizzati anche per "operazioni a lungo termine" di un paio di secondi. Fidati di me, non vuoi che tutto ciò che richiede così tanto tempo sia in esecuzione su un thread di dispacciamento o GUI.

Ho oltre 90 sistemi basati su dispositivi mobili che utilizzano socket asincroni per la comunicazione a un server e svolge un lavoro eccellente: molto più veloce dei servizi Web (ricordate comunque tutti i protocolli Web eseguiti su uno Socket), facile da rilevare errori ecc. ecc.

Faccio lo stesso sul mio codice server (mescolato con altri WCF per i pezzi di comunicazione middleware e back-end) ed è il comando più scalabile che abbiamo usato. Dovrai fare un Google su di esso, ma c'è un ragazzo che ha pubblicato i suoi test usando questa tecnologia ed è stato in grado di supportare 1.000 comunicazioni simultanee a un server con solo 11 thread. Non male.

Server esempio da MS: http://msdn.microsoft.com/en-us/library/fx6588te.aspx

esempio client da MS: http://msdn.microsoft.com/en-us/library/bew39x2a.aspx

Ci vuole più di questi per farlo "perfezionato", ma questo è un buon punto di partenza.

+1

L'articolo su http: // www.codeproject.com/KB/threads/threadtests.aspx sembra indicare che .NET ThreadPool ha problemi di prestazioni se si esegue una lunga elaborazione nei thread del thread thread (come i gestori di completamento delle chiamate asincroni). Questo problema non è stato visibile per te? – Sander

+0

Non riesco davvero a parlare con tempi di elaborazione davvero lunghi, ma da una prospettiva di comunicazione Socket non abbiamo mai avuto problemi. Tutte le nostre comunicazioni seguono un approccio asynch tamponato, e persino una trasmissione di grandi dimensioni ... diciamo un gig di dati, che su una piattaforma mobile può richiedere molto tempo, finché la rete è solida, gli zoccoli si sono dimostrati affidabili. Ironia della sorte, quasi ogni tecnologia di comunicazione in rete utilizza Socket al di sotto di un'astrazione più elevata per gestire il sollevamento pesante (di solito non è disponibile in dispositivi mobili, però). – BonanzaDriver

+0

@Sander: nel 2003 ThreadPool aveva un valore predefinito di 25 thread per CPU in esso (e la maggior parte dei computer era single core). Ora il valore predefinito è 250 per CPU, quindi ci sono meno problemi di quanti ce ne fossero: http://msdn.microsoft.com/en-us/library/system.threading.threadpool(v=VS.90).aspx (e .net 4 lo prende fino a 1023 per CPU su 32 bit e 32768 per CPU su 64 bit!) –

1

Ho ripetuto gli esperimenti di un CodeProject article on this topic e ho trovato i risultati per .NET 4 simili a quelli descritti nel 2003. Si noti che l'articolo non ha effettivamente elencato i risultati per la sezione problematica ma, come ho capito, il principale il problema esiste ancora.

Ho riutilizzato il codice dall'articolo CodeProject - basta scaricarlo per eseguire da solo questo test o per sperimentare.

Il test tenterà di utilizzare 10 thread paralleli per contare quanto più in alto possibile in 1 secondo.

Uso 10 thread in background (cioè new Thread())

 
T0 = 4451756 
T1 = 4215159 
T2 = 5449189 
T3 = 6244135 
T4 = 3297895 
T5 = 5302370 
T6 = 5256763 
T7 = 3779166 
T8 = 6309599 
T9 = 6236041 
Total = 50542073 

Utilizzando elementi di lavoro 10 ThreadPool

 
T0 = 23335890 
T1 = 20998989 
T2 = 22920781 
T3 = 9802624 
T4 = 0 
T5 = 0 
T6 = 0 
T7 = 0 
T8 = 0 
T9 = 0 
Total = 77058284 

notare che solo 4 filettatura elementi di lavoro piscina di 10 mai effettivamente eseguiti durante il primo intervallo di tempo! Si tratta di una CPU quad-core, quindi era un thread per core.Le altre attività eseguite dopo i primi quattro completati e poiché il 1 secondo assegnato era già scaduto, non incrementavano i loro contatori.

La conclusione qui: con attività lunghe, ThreadPool farà aspettare alcune attività dietro gli altri! Pertanto, si consiglia vivamente di non eseguire elaborazioni lunghe in attività ThreadPool (come i gestori di completamento asincroni). In caso contrario, è possibile mantenere il completamento delle chiamate asincrone più importanti se l'elaborazione dei dati esegue il hogging della CPU o si potrebbero avere prestazioni molto instabili se solo alcune attività eseguono molta elaborazione.

che utilizzano le specifiche ThreadPool personalizzato da articolo

 
T0 = 7175934 
T1 = 6983639 
T2 = 5306292 
T3 = 5078502 
T4 = 3279956 
T5 = 8116320 
T6 = 3262403 
T7 = 7678457 
T8 = 8946761 
T9 = 8500619 
Total = 64328883 
+1

Quello che ti sei perso dai risultati è che la versione di ThreadPool ha ottenuto risultati significativamente migliori rispetto alla versione non-threadpool di circa il 50%! L'articolo diceva che l'uso del ThreadPool era molto più lento, ma non è più così. Come per ogni cosa in programmazione, però, dipende "dipende". Se non è necessario avviare immediatamente l'esecuzione, è possibile utilizzare ThreadPool e terminare più rapidamente a causa di una minore commutazione di contesto, altrimenti è possibile gestirlo autonomamente. –

+0

@Matthew: Sì, sono d'accordo sul fatto che ThreadPool contati di più qui, ma non sono d'accordo sul motivo. Il motivo per cui ThreadPool conta di più è che i quattro thread ThreadPool esistono già, mentre con i nuovi thread creati manualmente, ci vuole molto tempo perché il thread inizi effettivamente. Quindi invertirò le tue conclusioni: se le tue attività non devono essere eseguite immediatamente, usa una nuova Discussione; se è necessario eseguire immediatamente, utilizzare ThreadPool (e non utilizzarlo con attività lunghe). – Sander

Problemi correlati