我正在尝试开发一个实现松散定义的环境上下文模式的库。我需要同时考虑高度并行性和远程处理 ( .NET Framework 4.6.2
)。看来我有 2 个选项可用:AsyncLocal<T>
和CallContext
. 我不相信两者都满足这两个考虑。
考虑以下示例,该示例演示了我的问题的远程处理部分:
class Program
{
static string hello = "Hello from '{0}'! \n\tAsyncID: {1} \n\tContextID: {2} ";
static void Main(string[] args)
{
OperationManager.CallContextOperationID = Guid.NewGuid();
OperationManager.AsyncLocalOperationID = Guid.NewGuid();
AppDomain other = AppDomain.CreateDomain("remote");
SayHello();
other.DoCallBack(SayHello);
Console.ReadKey();
}
private static void SayHello()
{
string statement = string.Format(hello, AppDomain.CurrentDomain.FriendlyName,
OperationManager.AsyncLocalOperationID,
OperationManager.CallContextOperationID);
Console.WriteLine(statement);
}
}
internal class OperationManager
{
private static string _slotName = "HelloWorld";
private static readonly AsyncLocal<Guid> _operationID = new AsyncLocal<Guid>();
public static Guid AsyncLocalOperationID
{
get => _operationID.Value;
set => _operationID.Value = value;
}
public static Guid CallContextOperationID
{
get => (Guid)CallContext.LogicalGetData(_slotName);
set => CallContext.LogicalSetData(_slotName, value);
}
}
此类创建两个 GUID,一个存储在异步本地,另一个存储在逻辑调用上下文中。然后它启动一个新的 AppDomain,并打印来自当前和远程域的值。
该程序的示例输出显示
Hello from 'ConsoleApp1.exe'!
AsyncID: 4c9e7c3a-fef8-4948-b0f0-896abe7dc2dd
ContextID: 4b479195-6fe8-43ae-a753-2fb3ccc57530
Hello from 'remote'!
AsyncID: 00000000-0000-0000-0000-000000000000
ContextID: 4b479195-6fe8-43ae-a753-2fb3ccc57530
我们可以看到 CallContext 跨越了远程边界,而 AsyncLocal 没有(并不奇怪)。
问题在于,由于 CallContext 跨线程共享的方式,我不相信我可以在“简单并行”环境中利用 CallContext(正如Stephen Cleary 在这篇文章中所阐述的那样)。Stephen 在链接解决方案中有一个出色的伪代码示例,我不会在此重复。该示例概述了我的问题的异步部分。
然后我的两个选择变成
AsyncLocal<T>
:在“简单并行”环境中工作,但无法跨越远程边界。
CallContext
:跨远程边界工作,但在“简单并行”环境中失败。
我错过了第三种选择吗?