如何不在 Task.Factory.StartNew 中传播 Activity
How to not propagate Activity in Task.Factory.StartNew
我有以下代码:
Task task = null;
var channel = System.Threading.Channels.Channel.CreateUnbounded<string>();
using (var activity = MyActivitySource.StartActivity("Parent"))
{
task = Task.Factory.StartNew(async () =>
{
//Activity.Current = null;
var item = await channel.Reader.ReadAsync();
Console.WriteLine("Task: {0}", Activity.Current?.DisplayName);
});
}
Console.WriteLine("Current end: {0}", Activity.Current?.DisplayName ?? "(null)");
await channel.Writer.WriteAsync("something");
await task;
我想在不注入 Activity 的情况下开始任务。
我无法在 using(var acrivity...) 之外创建任务。
一个选项(我想)是在任务开始时设置 Activity.Current = null。
有其他选择吗?
One option (I suppose) is setting Activity.Current = null at the beginning of the task. Is there an alternative option?
我的首选解决方案是将“处理”代码移动到单独的 top-level 循环中。即,将当前在 StartNew
中的代码移动到一个完全独立的方法中,将其包装在 await foreach (var item in channel.Reader.ReadAllAsync())
中,并在您启动频道时启动该循环。因此,本质上使它成为某种 ActionBlock
。
您可能需要使用其他值来扩充当前的 string
项目才能使其发挥作用。即,如果您需要 per-item 完成,那么您可以将 string
替换为 (string Item, TaskCompletionSource Completion)
。
还有另一种解决方案可能有效(但我真的建议改用 top-level 循环):您可以抑制逻辑上下文流(抑制 all AsyncLocal
-样式值)。但是我会建议确保任务在让它逃离那个块之前在线程池线程上启动,。所以看起来像这样:
using (var activity = MyActivitySource.StartActivity("Parent"))
{
using var suppressFlow = ExecutionContext.SuppressFlow();
var taskStarted = new TaskCompletionSource(TaskCreationOptions.ExecuteContinuationsAsynchronously);
task = Task.Run(async () =>
{
taskStarted.TrySetResult();
var item = await channel.Reader.ReadAsync();
Console.WriteLine("Task: {0}", Activity.Current?.DisplayName);
});
}
但实际上,我认为放入“主循环”会更好。
我有以下代码:
Task task = null;
var channel = System.Threading.Channels.Channel.CreateUnbounded<string>();
using (var activity = MyActivitySource.StartActivity("Parent"))
{
task = Task.Factory.StartNew(async () =>
{
//Activity.Current = null;
var item = await channel.Reader.ReadAsync();
Console.WriteLine("Task: {0}", Activity.Current?.DisplayName);
});
}
Console.WriteLine("Current end: {0}", Activity.Current?.DisplayName ?? "(null)");
await channel.Writer.WriteAsync("something");
await task;
我想在不注入 Activity 的情况下开始任务。 我无法在 using(var acrivity...) 之外创建任务。
一个选项(我想)是在任务开始时设置 Activity.Current = null。 有其他选择吗?
One option (I suppose) is setting Activity.Current = null at the beginning of the task. Is there an alternative option?
我的首选解决方案是将“处理”代码移动到单独的 top-level 循环中。即,将当前在 StartNew
中的代码移动到一个完全独立的方法中,将其包装在 await foreach (var item in channel.Reader.ReadAllAsync())
中,并在您启动频道时启动该循环。因此,本质上使它成为某种 ActionBlock
。
您可能需要使用其他值来扩充当前的 string
项目才能使其发挥作用。即,如果您需要 per-item 完成,那么您可以将 string
替换为 (string Item, TaskCompletionSource Completion)
。
还有另一种解决方案可能有效(但我真的建议改用 top-level 循环):您可以抑制逻辑上下文流(抑制 all AsyncLocal
-样式值)。但是我会建议确保任务在让它逃离那个块之前在线程池线程上启动,
using (var activity = MyActivitySource.StartActivity("Parent"))
{
using var suppressFlow = ExecutionContext.SuppressFlow();
var taskStarted = new TaskCompletionSource(TaskCreationOptions.ExecuteContinuationsAsynchronously);
task = Task.Run(async () =>
{
taskStarted.TrySetResult();
var item = await channel.Reader.ReadAsync();
Console.WriteLine("Task: {0}", Activity.Current?.DisplayName);
});
}
但实际上,我认为放入“主循环”会更好。