1

我正在尝试开发一个实现松散定义的环境上下文模式的库。我需要同时考虑高度并行性远程处理 ( .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:跨远程边界工作,但在“简单并行”环境中失败。

我错过了第三种选择吗?

4

0 回答 0