AsyncLocal&CallContext-如何同时实现异步和远程逻辑上下文保证?

时间:2018-09-24 23:40:41

标签: c# multithreading remoting callcontext ambientcontext

我正在尝试开发一个实现松散定义的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>:可跨越远程边界,但在“简单并行性”环境中失败。

  

我在这里还有第三种选择吗?

0 个答案:

没有答案