gpt4 book ai didi

c# - 跟踪 c#/.NET 任务流

转载 作者:太空狗 更新时间:2023-10-29 17:40:14 27 4
gpt4 key购买 nike

我正在尝试找到一种方法来跟踪异步任务的执行流程,以便于理解有关任务的方式,启动它的原始流程是什么。我主要需要它来记录、调试和保存特定执行流的某种堆栈跟踪。

例如:如果我的服务器有来自多个 IP 的许多客户端,并且服务器需要为每个客户端执行一个涉及许多异步操作的工作流,因此每个执行流涉及许多不同的任务;记录这样的流程很困难,尤其是在使用 async/await 机制时。

我还没有想出一种方法来包装任务,以便对于执行的每个任务我都知道记录时的初始流程描述。例如,如果我为一个带有描述的操作开始一个新的任务流程——“照顾 10.0.3.4 客户端”,我希望能够为从这个流程中产生的每个日志项添加这个描述,在从它创建的任何任务中.

当只使用线程时,这很容易,因为你有线程静态变量。任务是不可能的...我什至尝试创建自己的任务调度程序,它将包装任何使用它的任务(即使在使用 async/await 方法时)但陷入死胡同,因为任务调度程序基础有时会使用新线程(即使没有任何使用新线程的隐式请求)- TryExecuteTaskInline 方法有时可以在新线程中运行。

关于如何实现该目标的任何想法或建议?

最佳答案

您可以使用 Trace.CorrelationManager.ActivityId存储逻辑操作 ID,或者更好地存储 ImmutableStack逻辑操作 ID。它存储在 CallContext 中并通过 async 方法调用复制:

public static class LogicalFlow
{
private static readonly string _name = typeof (LogicalFlow).Name;

private static ImmutableStack<Guid> LogicalStack
{
get
{
return CallContext.LogicalGetData(_name) as ImmutableStack<Guid> ?? ImmutableStack.Create<Guid>();
}
set
{
CallContext.LogicalSetData(_name, value);
}
}

public static Guid CurrentId
{
get
{
var logicalStack = LogicalStack;
return logicalStack.IsEmpty ? Guid.Empty : logicalStack.Peek();
}
}
}

您可以将它用作 IDisposable,这样您就可以利用 using 范围来确保每个 Push 都有一个 Pop :

private static readonly Popper _popper = new Popper();

public static IDisposable StartScope()
{
LogicalStack = LogicalStack.Push(Guid.NewGuid());
return _popper;
}

private sealed class Popper : IDisposable
{
public void Dispose()
{
LogicalStack = LogicalStack.Pop();
}
}

用法:

using (LogicalFlow.StartScope())
{
Console.WriteLine(LogicalFlow.CurrentId);
await DoSomethingAsync();
Console.WriteLine(LogicalFlow.CurrentId);
}

这个答案以前依赖于 Trace.CorrelationManager.LogicalOperationStackIs LogicalOperationStack incompatible with async in .Net 4.5

关于c# - 跟踪 c#/.NET 任务流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24468894/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com