.NET 4.6 introduce la classe AsyncLocal<T>
per il flusso dei dati ambientali lungo il flusso asincrono del controllo. In precedenza ho usato CallContext.LogicalGet/SetData
per questo scopo, e mi chiedo se e in che modo i due sono semanticamente diversi (al di là delle ovvie differenze API come la tipizzazione forte e la mancanza di affidamento sulle chiavi stringa).In che modo la semantica di AsyncLocal differisce dal contesto della chiamata logica?
risposta
La semantica è praticamente la stessa. Entrambi sono memorizzati nel ExecutionContext
e passano attraverso chiamate asincrone.
Le differenze sono le modifiche API (proprio come hai descritto) insieme alla possibilità di registrare un callback per le modifiche di valore.
Tecnicamente, c'è una grande differenza nella realizzazione come il CallContext
viene clonato ogni volta che viene copiato (utilizzando CallContext.Clone
) mentre i dati s' il AsyncLocal
è conservato nel dizionario ExecutionContext._localValues
e proprio questo riferimento viene copiato senza alcun lavoro supplementare .
Per assicurarsi che gli aggiornamenti influiscano solo sul flusso corrente quando si modifica il valore di AsyncLocal
, viene creato un nuovo dizionario e tutti i valori esistenti vengono copiati in superficie in quello nuovo.
Questa differenza può essere positiva o negativa per le prestazioni, a seconda di dove viene utilizzato lo AsyncLocal
.
Ora, come Hans Passant accennato nei commenti CallContext
era originariamente per la comunicazione remota, e non è disponibile dove la comunicazione remota non è supportato (ad esempio Net Core), che è probabilmente il motivo per AsyncLocal
è stato aggiunto al quadro:
#if FEATURE_REMOTING
public LogicalCallContext.Reader LogicalCallContext
{
[SecurityCritical]
get { return new LogicalCallContext.Reader(IsNull ? null : m_ec.LogicalCallContext); }
}
public IllogicalCallContext.Reader IllogicalCallContext
{
[SecurityCritical]
get { return new IllogicalCallContext.Reader(IsNull ? null : m_ec.IllogicalCallContext); }
}
#endif
Nota: c'è anche un AsyncLocal
in Visual Studio SDK che è fondamentalmente un wrapper sopra CallContext
che mostra come simili i concetti sono: System.Threading.AsyncLocal.
sto chiedendo se e in che modo i due sono semanticamente differenti
Da quanto si vede, sia CallContext
e AsyncLocal
internamente relè ExecutionContext
per memorizzare i dati interni in un Dictionary
. Quest'ultimo sembra aggiungere un altro livello di riferimento per le chiamate asincrone. CallContext
è in giro da .NET Remoting ed era un modo conveniente per far scorrere i dati tra le chiamate asincrone dove non esisteva una vera alternativa, fino ad ora.
La differenza più grande che posso riconoscere è che AsyncLocal
ora consente di registrare per le notifiche tramite un callback quando un valore memorizzato sottostante viene modificato, sia da un interruttore ExecutionContext
o esplicitamente sostituendo un valore esistente.
// AsyncLocal<T> also provides optional notifications
// when the value associated with the current thread
// changes, either because it was explicitly changed
// by setting the Value property, or implicitly changed
// when the thread encountered an "await" or other context transition.
// For example, we might want our
// current culture to be communicated to the OS as well:
static AsyncLocal<Culture> s_currentCulture = new AsyncLocal<Culture>(
args =>
{
NativeMethods.SetThreadCulture(args.CurrentValue.LCID);
});
Oltre a questo, uno risiede in System.Threading
mentre le altre vite in System.Runtime.Remoting
, dove il primo sarà supportato in CoreCLR.
Inoltre, non sembra che lo AsyncLocal
abbia la semantica copy-on-write poco profonda SetLogicalData
, quindi i dati fluiscono tra le chiamate senza essere copiati.
Sembra esserci una differenza semantica nel tempo.
Con CallContext la modifica del contesto avviene quando viene impostato il contesto per il metodo figlio/task/asincrono, ad esempio quando vengono chiamati il metodo Task.Factory.StartNew(), Task.Run() o async.
Con AsyncLocal, la modifica del contesto (modifica chiamata callback di notifica in corso) si verifica quando il metodo figlio/argomento/asincrono inizia effettivamente l'esecuzione.
La differenza di temporizzazione potrebbe essere interessante, soprattutto se si desidera che l'oggetto di contesto venga clonato quando si cambia il contesto. L'utilizzo di diversi meccanismi potrebbe causare la clonazione di diversi contenuti: con CallContext si clona il contenuto quando viene creato il thread/attività secondario o viene chiamato il metodo async; ma con AsyncLocal cloni il contenuto quando il metodo figlio/argomento/asincrono inizia l'esecuzione, il contenuto dell'oggetto contesto potrebbe essere stato modificato dal thread padre.
Interessante. C'è uno snippet di codice veloce che potresti pubblicare per dimostrare questa differenza? – ChaseMedallion
Storicamente (prima di .Net 4.6) abbiamo dovuto hackerare uno slot speciale su CallContext in modo che la struttura dei dati contestuali sia clonata quando viene cambiato il contesto della chiamata. Il programma dimostrativo mostra che con CallContext la clonazione avviene sul thread chiamante, rispetto a AsyncLocal il gestore di notifica delle modifiche viene richiamato sul thread chiamato. https://1drv.ms/u/s!AuD-2O_ZRWVijzXBVJTKbQeWCTzc – WenningQiu
- 1. In che modo Dispatcher differisce dal thread in background?
- 2. Come limitare l'ambito di un contesto di chiamata logica
- 3. Chiamata ambigua dal contesto statico in Java
- 4. L'anteprima della storyboard differisce dal simulatore
- 5. semantica degli operatori booleani e di confronto nel contesto di tre valori-logica
- 6. In che modo Rust fornisce la semantica del movimento?
- 7. In che modo XACML 3.0 differisce da XACML 2.0?
- 8. Che cos'è la "semantica formale"?
- 9. Passaggio del contesto della chiamata logica dalla pipeline OWIN al controller WebApi
- 10. In che modo \ v differisce da \ x0b o \ x0c?
- 11. C# Async/Attendi: lascia il contesto AsyncLocal <T> in fase di creazione dell'attività
- 12. In che modo Clojure STM differisce da Haskell STM?
- 13. In che modo l'operatore "|| =" differisce da "? =" In CoffeeScript?
- 14. In che modo il caricamento differisce da richiedere in Ruby?
- 15. chiamata di funzione con differenti semantica
- 16. Qual è la logica dietro il contesto zeroMQ?
- 17. In che modo la densità di ggplot2 differisce dalla funzione di densità?
- 18. L'utilizzo della memoria segnalato da guppy differisce dal comando ps
- 19. Come mantenere la logica di visualizzazione fuori dal modello e dalla logica aziendale dal modello di visualizzazione in MVVM?
- 20. In che modo breeze.js gestisce la sicurezza ed evita di esporre la logica aziendale
- 21. C'è un modo per ascoltare un evento nel contesto fantasma dal contesto della pagina?
- 22. Lingue che ottimizzano l'utilizzo della programmazione logica
- 23. android - Come ottenere la vista dal contesto?
- 24. Ignora la schermata della chiamata in entrata?
- 25. In che modo la sintassi <> differisce da una normale durata?
- 26. Spostare la semantica in Eigen
- 27. Come separare la logica dell'applicazione dal livello di rete in Android utilizzando Retrofit 2
- 28. clojure richiede la logica della sintassi
- 29. Chiamata di sistema senza commutazione di contesto?
- 30. Perché e in che modo HashMap ha la propria implementazione interna di hashCode() chiamata hash()?
Non credo ci sia. È un'alternativa per progetti che non possono dipendere da CallContext perché hanno come target CoreCLR. CallContext richiede il supporto remoto, non disponibile nella versione CLR piccola. –
Dov'è @ stephen-cleary quando hai bisogno di lui? – batwad