.NET 4.6では、AsyncLocal<T>
制御の非同期フローに沿って周囲データを流すためのクラス。以前に使用したCallContext.LogicalGet/SetData
この目的のために、私は2つが意味的に異なるかどうか、どのように意味があるのか疑問に思っています(厳密な型指定や文字列キーへの依存の欠如などの明らかなAPIの違いを超えて)。
セマンティクスはほとんど同じです。両方ともExecutionContext
に保存され、非同期呼び出しを介して流れます。
違いは、APIの変更(説明したとおり)と、値の変更のためにコールバックを登録する機能です。
技術的には、CallContext
はコピーされるたびに複製されるため、実装には大きな違いがあります(CallContext.Clone
)AsyncLocal
のデータはExecutionContext._localValues
辞書とその参照だけが余分な作業なしでコピーされます。
AsyncLocal
の値を変更したときに更新が現在のフローにのみ影響するように、新しい辞書が作成され、既存の値はすべて新しいものに浅くコピーされます。
AsyncLocal
が使用される場所に応じて、その違いはパフォーマンスにとって良いことも悪いこともあります。
現在、Hans Passantがコメントで言及したように、CallContext
はもともとリモーティング用に作成されたもので、リモーティングがサポートされていない場所(たとえば.Net Core)では利用できないため、おそらくAsyncLocal
が追加されましたフレームワークへ:
#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
注:Visual Studio SDKには、基本的にAsyncLocal
のラッパーであるCallContext
もあり、概念がどのように似ているかを示します: Microsoft.VisualStudio.Threading 。
私は2つが意味的に異なるかどうか、どのような方法で疑問に思っています
見ることができることから、CallContext
とAsyncLocal
の両方は、ExecutionContext
に内部データを保存するためにDictionary
に内部的に依存しています。後者は、非同期呼び出しに別のレベルの間接参照を追加しているようです。 CallContext
は.NET Remoting以来使用されており、これまで実際の代替手段がなかった非同期呼び出し間でデータを流す便利な方法でした。
見つけられる最大の違いは、AsyncLocal
により、基になる保存された値が変更されたときに、ExecutionContext
スイッチによって、または既存の値を明示的に置き換えることによって、コールバック経由で通知に登録できるようになったことです。
// 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);
});
それ以外は、System.Threading
もう一方はSystem.Runtime.Remoting
、前者はCoreCLRでサポートされます。
また、AsyncLocal
が浅いコピーオンライトセマンティクスSetLogicalData
を持っているとは思われないため、データはコピーされずに呼び出し間を流れます。
タイミングに意味的な違いがあるように見えます。
CallContextでは、子スレッド/タスク/非同期メソッドのコンテキストが設定されたとき、つまりTask.Factory.StartNew()、Task.Run()またはasyncメソッドが呼び出されたときに、コンテキストの変更が発生します。
AsyncLocalでは、子スレッド/タスク/非同期メソッドが実際に実行を開始すると、コンテキストの変更(呼び出される変更通知コールバック)が発生します。
特に、コンテキストが切り替えられたときにコンテキストオブジェクトを複製する場合は、タイミングの違いが興味深い場合があります。異なるメカニズムを使用すると、異なるコンテンツが複製される可能性があります。CallContextを使用すると、子スレッド/タスクの作成時または非同期メソッドの呼び出し時にコンテンツを複製できます。ただし、AsyncLocalを使用すると、子スレッド/タスク/非同期メソッドが実行を開始したときにコンテンツを複製します。コンテキストオブジェクトのコンテンツは、親スレッドによって変更されている可能性があります。