credo che il TPL (TaskFactory.Startnew) funziona in modo simile a ThreadPool.QueueUserWorkItem in che ho t accoda il lavoro su un thread nel pool di thread.
Pretty much.
Da quello che ho letto sembra che async/attenda solo "qualche volta" crea un nuovo thread.
In realtà, non lo fa mai. Se vuoi il multithreading, devi implementarlo tu stesso. C'è un nuovo metodo Task.Run
che è solo una scorciatoia per Task.Factory.StartNew
ed è probabilmente il modo più comune di avviare un'attività nel pool di thread.
Se si trattava di porte di completamento IO, è possibile vederlo non dover creare un nuovo thread, ma altrimenti penserei che sarebbe necessario.
Bingo. Pertanto, metodi come Stream.ReadAsync
creeranno effettivamente un wrapper Task
attorno a un IOCP (se lo Stream
dispone di un IOCP).
È inoltre possibile creare alcune "attività" non di I/O, senza CPU. Un semplice esempio è Task.Delay
, che restituisce un'attività che termina dopo un certo periodo di tempo.
La cosa più cool async
/await
è che si può coda po 'di lavoro al pool di thread (per esempio, Task.Run
), fare un po' mi funzionamento/O-bound (ad esempio, Stream.ReadAsync
), e fare qualche altra operazione (ad esempio, Task.Delay
) ... e sono tutte attività! Possono essere attesi o utilizzati in combinazioni come Task.WhenAll
.
Qualsiasi metodo che restituisce Task
può essere await
ed - non deve essere un metodo async
. Pertanto, le operazioni Task.Delay
e I/O utilizzano solo TaskCompletionSource
per creare e completare un'attività: l'unica cosa che viene eseguita nel pool di thread è il completamento effettivo dell'attività quando si verifica l'evento (timeout, completamento dell'I/O, ecc.).
Suppongo che la mia comprensione di FromCurrentSynchronizationContext sia sempre stata un po 'confusa. Ho sempre capito che era, in sostanza, il thread dell'interfaccia utente.
Ho scritto an article su SynchronizationContext
. La maggior parte delle volte, SynchronizationContext.Current
:
- è un contesto dell'interfaccia utente se il thread corrente è un thread dell'interfaccia utente.
- è un contesto di richiesta ASP.NET se il thread corrente sta servendo una richiesta ASP.NET.
- è altrimenti un contesto di pool di thread.
Qualsiasi discussione può impostare il proprio SynchronizationContext
, quindi non ci sono eccezioni alle regole di cui sopra.
noti che l'awaiter predefinita Task
programmerà il resto del metodo async
sulla corrente SynchronizationContext
se non è nullo; altrimenti va sull'attuale TaskScheduler
. Oggi non è così importante, ma nel prossimo futuro sarà una distinzione importante.
Ho scritto il mio async
/await
intro sul mio blog e Stephen Toub ha pubblicato di recente un eccellente async
/await
FAQ.
Per "concorrenza" o "multithreading", vedere this related SO question. Direi che async
abilita la concorrenza, che può essere o non essere multithread. È facile utilizzare await Task.WhenAll
o await Task.WhenAny
per eseguire l'elaborazione simultanea e, a meno che non si utilizzi esplicitamente il pool di thread (ad esempio, Task.Run
o ConfigureAwait(false)
), è possibile avere contemporaneamente più operazioni simultanee in corso (ad esempio, più I/O o altro tipi come Delay
) - e non c'è nessun thread necessario per loro. Io uso il termine "concorrenza a thread singolo" per questo tipo di scenario, anche se in un host ASP.NET, si può effettivamente finire con "zero -threaded concurrency". Che è piuttosto dolce
In realtà, TaskCreationOptions.LongRunning non garantisce un "nuovo thread". Per MSDN, * l'opzione "LongRunning" fornisce solo un suggerimento allo scheduler; non garantisce un thread dedicato. * L'ho trovato nel modo più duro. – eduncan911
@ eduncan911 anche se quello che dici sulla documentazione è corretto, ho cercato il codice sorgente TPL qualche tempo fa e sono abbastanza sicuro che in realtà un nuovo thread dedicato viene sempre creato quando è specificato 'TaskCreationOptions.LongRunning'. –
@ZaidMasud: potresti voler dare un'altra occhiata.So che stava raggruppando i thread perché 'Thread.CurrentThread.IsThreadPoolThread' restituiva true per thread a esecuzione ridotta di poche centinaia di millisecondi. per non parlare delle variabili ThreadStatic che stavo usando emorragia in più thread, causando ogni sorta di havok. Ho dovuto forzare il mio codice a nuovi thread multipli(), il vecchio modo, per garantire un thread dedicato. In altre parole, non potrei usare la TaskFactory per i thread dedicati. Opzionalmente, potresti implementare il tuo 'TaskScheduler' che restituisce sempre un thread dedicato. – eduncan911