gpt4 book ai didi

c# - TaskScheduler.Default 不总是保证任务将在池线程上执行吗?

转载 作者:太空狗 更新时间:2023-10-30 01:04:02 24 4
gpt4 key购买 nike

TaskScheduler.Default 总是保证任务将在池线程上执行吗?

在修复 bug 时,我至少发现了一个没有修复的情况。它可以像这样重现(一个由真实代码制作的人为示例):

var tcs = new TaskCompletionSource<bool>();
var sc = SynchronizationContext.Current;
sc.Post(_ => tcs.SetResult(true), null);
await tcs.Task.ContinueWith(_ =>
{
// breaks here
Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

还有其他情况吗?

此外,是否有一种优雅的方法来确保 ContinueWith 操作同步执行,如果前面的任务已在池线程上完成,或者在其他情况下排队到线程池(我知道我可以在 ContinueWith 操作中使用 QueueUserWorkItem,但我不喜欢它)。

已编辑,我想我可以实现自己的 TaskScheduler 并检查我是否已经在 TryExecuteTaskInline 中的线程池线程上,以控制它。

最佳答案

我认为发生这种情况的原因是因为您使用了 TaskContinuationOptions.ExecuteSynchronously。来自 doco:

ExecuteSynchronously Specifies that the continuation task should be executed synchronously. With this option specified, the continuation will be run on the same thread that causes the antecedent task to transition into its final state. If the antecedent is already complete when the continuation is created, the continuation will run on the thread creating the continuation. Only very short-running continuations should be executed synchronously.

如果前面的任务在线程池线程以外的线程上完成,那么延续也将在该线程上运行。所以我想在那种情况下不会发生调度。另一种情况可能是延续任务已经完成,它也将同步运行。

更新

为了实现您在问题的第二部分中提出的要求,我认为您需要一个自定义服务员。参见 this articl e 了解更多详细信息,但类似这样的内容可能对您有用:

public static class Extensions
{
public static ThreadPoolTaskAwaiter WithThreadPool(this Task task)
{
return new ThreadPoolTaskAwaiter(task);
}

public class ThreadPoolTaskAwaiter : INotifyCompletion
{
private readonly TaskAwaiter m_awaiter;

public ThreadPoolTaskAwaiter(Task task)
{
if (task == null) throw new ArgumentNullException("task");
m_awaiter = task.GetAwaiter();
}

public ThreadPoolTaskAwaiter GetAwaiter() { return this; }

public bool IsCompleted { get { return m_awaiter.IsCompleted; } }

public void OnCompleted(Action continuation)
{
if (Thread.CurrentThread.IsThreadPoolThread)
{
continuation();
}
else
{
Task.Run(continuation);
}
}

public void GetResult()
{
m_awaiter.GetResult();
}
}
}

然后你像这样使用它:

public static async Task Execute()
{
await Task.Delay(500).WithThreadPool();

// does not break here
if (!Thread.CurrentThread.IsThreadPoolThread)
{
Debugger.Break();
}
}

关于c# - TaskScheduler.Default 不总是保证任务将在池线程上执行吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25101709/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com