.NET 4.6 wprowadza klasę AsyncLocal<T>
dla przepływu danych otoczenia wzdłuż asynchronicznego przepływu sterowania. Wcześniej używałem do tego celu CallContext.LogicalGet/SetData
i zastanawiam się, czy iw jaki sposób te dwie są semantycznie odmienne (poza oczywistymi różnicami API, takimi jak silne pisanie i brak zaufania do kluczy strunowych).W jaki sposób semantyka AsyncLocal różni się od kontekstu połączenia logicznego?
Odpowiedz
Semantyka to prawie to samo. Oba są przechowywane w ExecutionContext
i przepływają przez połączenia asynchroniczne.
Różnice dotyczą zmian API (zgodnie z opisem) wraz z możliwością zarejestrowania wywołania zwrotnego dla zmian wartości.
Technicznie rzecz biorąc, istnieje duża różnica w realizacji co CallContext
klonuje się za każdym razem jest on skopiowany (za pomocą CallContext.Clone
) podczas przesyłania danych przez AsyncLocal
„s jest trzymane w słowniku ExecutionContext._localValues
i właśnie to odniesienie jest kopiowane bez jakiejkolwiek dodatkowej pracy .
Aby upewnić się, że aktualizacje wpływają na bieżący przepływ po zmianie wartości AsyncLocal
, tworzony jest nowy słownik, a wszystkie istniejące wartości są płytko kopiowane na nowy.
Ta różnica może być zarówno dobra, jak i zła pod względem wydajności, w zależności od tego, gdzie użyto AsyncLocal
.
Teraz, jak Hans Passant wspomniano w komentarzach CallContext
został pierwotnie stworzony do usług zdalnych, a nie jest dostępny gdzie remoting nie jest obsługiwane (np .Net rdzenia), które jest prawdopodobnie dlaczego AsyncLocal
dodano do ram:
#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
Uwaga: istnieje również AsyncLocal
w Visual Studio SDK, który jest zasadniczo otoki nad CallContext
który pokazuje, jak bardzo podobne koncepcje są: System.Threading.AsyncLocal.
Zastanawiam się, czy iw jaki sposób te dwie rzeczy są semantycznie różni
Z tego co widać, zarówno CallContext
i AsyncLocal
wewnętrznie przekaźnik na ExecutionContext
do przechowywania swoich danych wewnętrznych wewnątrz Dictionary
. Ta ostatnia wydaje się dodawać kolejny poziom pośrednictwa dla połączeń asynchronicznych. CallContext
istnieje od czasu .NET Remoting i był wygodnym sposobem przesyłania danych między asynchronicznymi połączeniami, gdzie nie było prawdziwej alternatywy, aż do teraz.
Największą różnicę można dostrzec, że AsyncLocal
teraz pozwala zarejestrować powiadomień poprzez oddzwonienie gdy bazowego wartość zapisana zostanie zmieniona, albo za pomocą przełącznika ExecutionContext
lub jawnie zastępując istniejącą wartość.
// 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);
});
Poza tym, jeden mieszka w System.Threading
natomiast drugi mieszka na System.Runtime.Remoting
, gdzie były wspierane będą w CoreCLR.
Ponadto nie wydaje się, aby AsyncLocal
miał płytką semantykę zapisu na zapis SetLogicalData
, więc dane przepływają między połączeniami bez kopiowania.
Wydaje się, że istnieje pewna semantyczna różnica w taktowaniu.
Z CallContext zmiana kontekstu zachodzi, gdy kontekst dla wątku potomnego/zadania/metody asynchronicznej jest skonfigurowany, tj. Gdy wywoływane są Task.Factory.StartNew(), Task.Run() lub metoda asynchroniczna.
Przy pomocy AsyncLocal następuje zmiana kontekstu (wywołanie wywołania zwrotnego powiadomień o zmianie), gdy metoda wątku/zadania/asynchronizacji faktycznie zaczyna działać.
Różnica w taktowaniu może być interesująca, szczególnie jeśli chcesz, aby obiekt kontekstu był klonowany przy zmianie kontekstu. Korzystanie z różnych mechanizmów może powodować klonowanie różnych treści: za pomocą CallContext klonujesz zawartość, gdy tworzony jest wątek potomny/zadanie lub wywoływana jest metoda asynchroniczna; ale z AsyncLocal klonujesz zawartość, gdy zaczyna się wykonywanie wątku potomnego/zadania/asynchronizacji, treść obiektu kontekstu mogła zostać zmieniona przez wątek nadrzędny.
Interesujące. Czy istnieje krótki fragment kodu, który możesz opublikować, który pokazuje tę różnicę? – ChaseMedallion
Historycznie (przed .Net 4.6) musieliśmy zhackować specjalny slot w CallContext, aby kontekstowa struktura danych została sklonowana po przełączeniu kontekstu połączenia. Program demonstracyjny pokazuje, że w przypadku CallContext klonowanie odbywa się w wątku wywołującym, w porównaniu z AsyncLocal procedura obsługi powiadomień o zmianach jest wywoływana w wywołanym wątku. https://1drv.ms/u/s!AuD-2O_ZRWVijzXBVJTKbQeWCTzc – WenningQiu
- 1. W jaki sposób operator "|| =" różni się od "? =" W CoffeeScript?
- 2. W jaki sposób rekursja pierwotna różni się od "normalnej" rekursji?
- 3. znaczenie tego GlassFish ostrzeżenia: ścieżka kontekstu różni się od wiązki
- 4. W jaki sposób MVVM w .Net różni się od MVC w kakao?
- 5. W jaki sposób in statyczna inicjalizacja statyczna floata różni się od int w C++?
- 6. W jaki sposób local() różni się od innych podejść do zamknięcia w R?
- 7. W jaki sposób pojęcie statyczne w języku Java różni się od C#?
- 8. W jaki sposób funkcja async-await w C# 5.0 różni się od licencji TPL?
- 9. Czym różni się ArrayListMultimap od LinkedListMultimap?
- 10. jQuery. W jaki sposób funkcja queue() różni się od funkcji wywołania zwrotnego, ponieważ coś jest zrobione?
- 11. W jaki sposób ADF stoi przed cyklem życia różni się od lifecylce JSF?
- 12. W jaki sposób websocket różni się od http z połączeniem nagłówka-keep-alive = million
- 13. W jaki sposób implementacja Table Data Gateway różni się od Active Record?
- 14. W jaki sposób rozdzielczość przeciążenia grupy metod różni się od rozdzielczości przeciążenia wywołania metody?
- 15. jaki sposób operator> + różni się od> = w SQL Server 2012
- 16. W jaki sposób minimalne drzewo obejmujące wąskie gardło różni się od minimalnego drzewa opinającego?
- 17. W jaki sposób Perforce ignoruje składnię pliku różni się od składni gitignore?
- 18. Kod źródłowy różni się od oryginalnej wersji
- 19. Czym różni się żądanie wyciągnięcia od oddziału?
- 20. Pandy: dlaczego pandas.Series.std() różni się od numpy.std()
- 21. Pandy: dlaczego pandas.Series.std() różni się od numpy.std()
- 22. Dlaczego [:] = 1 zasadniczo różni się od [:] = "1"?
- 23. Czym różni się okno od siebie?
- 24. Czym różni się insmod od modprobe?
- 25. Czym różni się LinkedBlockingQueue od ConcurrentLinkedQueue?
- 26. Maniak perłowy różni się od innych debli
- 27. Czym różni się aplikacja Facebook od karty?
- 28. Dlaczego "gevent.spawn" różni się od monkeypatched `threading.Thread()`?
- 29. Czym różni się Rakietowy od Planu?
- 30. Clojure: jak defn różni się od fn?
Nie sądzę, że istnieje. Jest to alternatywa dla projektów, które nie mogą polegać na CallContext, ponieważ są ukierunkowane na CoreCLR. CallContext wymaga wsparcia zdalnego, niedostępnego w małej wersji CLR. –
Gdzie jest @ stephen-cleary kiedy go potrzebujesz? – batwad