AsyncLocal & CallContext - Как я могу получить как асинхронные *, так и * удаленные гарантии логического контекста? - PullRequest
0 голосов
/ 25 сентября 2018

Я пытаюсь разработать библиотеку, которая реализует свободно определенный Шаблон окружающего контекста . Мне нужно учитывать как высокую степень параллелизма , так и удаленное взаимодействие (.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 является общим для всех потоков.У Стивена есть отличный пример псевдокода в связанном решении, который я не буду здесь дублировать.Этот пример обрисовывает в общих чертах асинхронную часть моей проблемы.

Мои два варианта становятся

AsyncLocal<T>: Работает в среде "простого параллелизма", но не проходит через границы удаленного взаимодействия.

CallContext: работает за пределами удаленного взаимодействия, но не работает в среде "простого параллелизма".

Есть ли здесь третий вариант, который мне не хватает?

...