等待Task.Run在退出时更改跟踪ActivityId

时间:2013-02-05 05:30:17

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

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

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

ActivityId已经从输入时改变了。在LongRunningMethod()中它是正确的(我在方法中有各种跟踪事件),它似乎只在await完成时改变。

我的问题是为什么ActivityId会改变?

这行代码位于使用async声明的函数中,而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方法?我基本上都想要所有的&#39; LongRunningMethod&#39;同时以异步方式启动,然后等到所有结束。

2 个答案:

答案 0 :(得分:10)

你做错了,但是不行。

在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

答案 1 :(得分:1)

目前尚不清楚您使用await关键字的原因。如果您不需要“继续”所需任务,请使用

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

在调用await之后,您可能会(但由于您提供的代码量很少而无法保证)您拥有代码。 await导致继续设置,将使用不同的同步上下文运行,该同步上下文用于运行将在后台线程池线程上运行的LongRunningMethod()

我希望这会有所帮助。