c# - 在异步调用中保留线程的上下文

标签 c#

我试图通过将我的日志消息分组在一起来理清我的日志。理想情况下,我会向每条消息附加一些标识符,表明它是完成某项工作的一组命令的一部分。

如果这是一个单线程应用程序,线程的 ID 将是一个候选者。但是,此解决方案大量使用异步 Task,这妨碍了它的使用。是否有可能使类似下面的东西起作用,其中 Main() 的每次执行都将始终打印出相同的线程 ID?

static async void Main()
{
    var t = Task.Run(async () => await MyAsyncMethod());
    await t;
}

private static async Task MyAsyncMethod()
{
  Debug.WriteLine("Log message: {0}", Thread.CurrentThread.ManagedThreadId);

  await Task.Delay(1000);

  Debug.WriteLine("Log message: {0}", Thread.CurrentThread.ManagedThreadId);

  await Task.Delay(1000);

  Debug.WriteLine("Log message: {0}", Thread.CurrentThread.ManagedThreadId);
}

最佳答案

IMO 的最佳方法是@SriramSakthivel 建议的方法:只需生成一个 ID 并将其传递。如果您有“消息”类型,则可以将其添加到该类型。

但是,如果这会导致过多的代码更改,那么您可以隐式传递它。我有一个 blog post with the gory details ;一般的想法是将数据存储为逻辑调用上下文的一部分:

public static class MyContext
{
  private static readonly string name = Guid.NewGuid().ToString("N");

  private sealed class Wrapper : MarshalByRefObject
  {
    public Guid Value { get; set; }
  }

  public static Guid CurrentContext
  {
    get
    {
      var ret = CallContext.LogicalGetData(name) as Wrapper;
      return ret == null ? Guid.Empty : ret.Value;
    }

    set
    {
      CallContext.LogicalSetData(name, new Wrapper { Value = value });
    }
  }
}

然后您可以在您的代码中使用它:

private static async Task MyAsyncMethod()
{
  MyContext.CurrentContext = Guid.NewGuid();

  Debug.WriteLine("Log message: {0}", MyContext.CurrentContext);

  await Task.Delay(1000);

  Debug.WriteLine("Log message: {0}", MyContext.CurrentContext);

  await Task.Delay(1000);

  Debug.WriteLine("Log message: {0}", MyContext.CurrentContext);
}

请注意,此方法做出了两个关键假设:

  1. 您的代码在 .NET 4.5 或更新版本上运行。
  2. 存储的数据是不可变的(在这种情况下是正确的,因为 Guid 是不可变的)。

看起来像这样will be builtin在 .NET 4.6 中。

关于c# - 在异步调用中保留线程的上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30038308/

相关文章:

c# - 等待线程完成的标准方法

c# - 使用 GL.LINES 和 Unity3d 绘制一条线

c# - Windows .NET/Win32 UI开发

c# - 检查编码中是否存在字符

c# - 异步/等待异常和 Visual Studio 2013 调试输出行为

c# - 使用Naudio.dll结束播放音频文件

c# - 在什么命名空间中找到 FileOutputStream

c# - 将属性绑定(bind)到父属性的值

c# - 表格最上面?

c# - 内联 If 语句 - 短路