我正在尝试开发一个实现松散定义的Ambient Context pattern的库。 我需要同时考虑高度并行性和远程处理(.NET Framework 4.6.2
)。看来我有2个可用选项:AsyncLocal<T>
和{ {1}}。我不相信这两个因素都满足。
请考虑以下示例,该示例演示了解决我的问题的另一半:
CallContext
此类创建两个GUID,一个存储在异步本地中,另一个存储在逻辑调用上下文中。然后,它启动一个新的AppDomain,并打印当前域和远程域中的值。
该程序的输出示例显示
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);
}
}
我们可以看到CallContext跨越了远程处理边界,而AsyncLocal却没有(不足为奇)。
问题在于,由于跨线程共享CallContext的方式,我不认为我可以在“简单并行”环境(如laid out by Stephen Cleary in this post)中利用CallContext。 Stephen在链接解决方案中有一个出色的伪代码示例,在这里我不会重复。该示例概述了我问题的异步部分。
然后我的两个选项变为
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
:在“简单并行性”环境中工作,但无法跨越远程边界。
AsyncLocal<T>
:可跨越远程边界,但在“简单并行性”环境中失败。
我在这里还有第三种选择吗?