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

标签 c# .net multithreading asynchronous task-parallel-library

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

例如:如果我的服务器有来自多个 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/

相关文章:

.net - 甲骨文错误 : TNS: Listener was not given the SERVICE_NAME in CONNECT_DATA 1

multithreading - iOS - 默认在哪个队列选择器上运行?

java swing线程问题

c# - 如何在发出请求之前将 WCF Http 客户端绑定(bind)到特定的出站 IP 地址

c# - 带有 using 语句的 SqlCommand

.net - 如何在 .Net 上处理不同的屏幕分辨率

java - 如何处理从Spring服务器调用的长异步存储过程?

C# 模式匹配数组

c# - 证书签名在服务器上产生不同的签名

c# - 在 FormClosing 方法中处理是/否/取消消息框中的取消按钮