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