【问题标题】:await Task.Run altering trace ActivityId on exit等待 Task.Run 在退出时更改跟踪 ActivityId
【发布时间】:2013-02-05 05:30:17
【问题描述】:

我正在尝试使用 Trace.CorrelationManager.ActivityId 来关联日志条目。但是,我发现这段代码何时完成:

var result = await Task.Run(() => LongRunningMethod());

ActivityId 与输入时的内容不同。虽然在 LongRunningMethod() 中它是正确的(我在方法中有各种跟踪事件),但它似乎只在等待完成时才会改变。

我的问题是为什么 ActivityId 发生了变化?

这行代码在一个用 async 声明的函数中,该函数又被 MVC 项目中的异步控制器操作调用:

async public Task<ActionResult> Index()
{
...
var tasks = {list of Download<T> delegates}

var result = await Task.WhenAll(tasks)
}


async public Task<OperationResult> Download<T>(IEnumerable<T> data, Device device)
{
...
var result = await Task.Run(() => LongRunningMethod());

return result
}

也许我错误地使用了 async/await 或 Task 方法?我基本上希望所有的“LongRunningMethod”同时异步启动,然后等到全部完成。

【问题讨论】:

  • 您使用的是 .NET 4.5 吗?
  • 问题是为什么ActivityId会改变。是的,使用 .NET 4.5

标签: c# task-parallel-library async-await tracesource


【解决方案1】:

你没有做错,但它不会起作用。

在 WCF 和 ASP.NET(包括 MVC)下,框架在执行请求之前,会捕获当前上下文,因此可以恢复它以确保完成在原始线程上运行。

不幸的是,这发生在您的控制器被调用之前。系统快照发生在您有机会更新 ActivityID 之前。在继续中,上下文将重置为您设置之前的值。

我发现,如果您将 .ConfigureAwait(false) 添加到您的任务中,则延续不必在原始上下文中运行,因此您的活动 ID 将被恢复。

目前我没有更好的解决方案,除了使用 CallContext.LogicalGetData/LogicalSetData 来管理您自己的 ActivityID。关于我在 EventSourceProxy 中的处理方式,见https://github.com/jonwagner/EventSourceProxy/commit/fa43c6acd07690dcd276346e3fcf25028f796b8c

这是一篇关于更深入解释的精彩文章。

http://sticklebackplastic.com/post/2007/08/14/One-mighty-gotcha-for-SystemDiagnostic-activity-Ids.aspx

【讨论】:

  • 你会说这种行为是特定于 ASP.NET/WCF 的吗?
  • 我不认为它特定于 ASP/WCF。我没有看框架代码,但我猜问题出在线程池的某个地方。
【解决方案2】:

不清楚您为什么使用await 关键字。如果您不需要“继续”所需任务,请使用

启动它
var result = Task.Factory.StartNew(() => LongRunningMethod());

在调用await 之后,很可能(但由于您提供的代码量很少,因此不能保证)您有代码。 await 导致设置一个延续,它将使用与运行 LongRunningMethod() 不同的同步上下文运行,后者将在后台线程池线程上运行。

我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-01
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 2012-11-12
    相关资源
    最近更新 更多