F#backgroundTask导致WPF UI冻结

问题描述 投票:0回答:2

我有一个 C# 语言的 WPF 应用程序 (.NET 8)。此应用程序调用 F# 库中的函数,此 F# 函数使用 backgroundTask 计算表达式启动任务:

let fun1() = ignore <| backgroundTask {
// long asynchronous work, no access elements, only internal memory
}

通过使用

backgroundTask
而不是
task
CE,我希望任务在单独的线程上运行,并且 不会影响 GUI 的响应能力。 但情况并非如此,该任务运行时 GUI 仍然冻结。

怎么了?

wpf asynchronous f#
2个回答
2
投票

您的场景中

SynchronizationContext.Current
的价值是多少?

来自 F# 文档

后台任务会在以下意义上忽略任何

SynchronizationContext.Current
:如果在具有非空
SynchronizationContext.Current
的线程上启动,它将使用
Task.Run
切换到线程池中的后台线程。如果在带有 null
SynchronizationContext.Current
的线程上启动,它将在同一线程上执行。

鉴于此解释,我怀疑您有一个 null

SynchronizationContext.Current
,因此您的代码正在启动它的线程上运行。 (我也发现这种行为令人惊讶,但至少它被记录下来。)


0
投票

经过一番调查,我终于在 GUI 中获得了所需的流畅性。这是我发现的:

  • 发布版本比调试版本具有更少的冻结副作用
  • 在附加调试器的情况下启动进程(Visual Studio 中的 F5)会恶化冻结效果
  • 任务中的代码正在迭代 IAsyncEnumerable<_>。最初我使用的是TaskSeq。我删除了它并使用枚举器和内置异步 CE 编写了迭代。这也改善了结果。

现在,如果我运行我的新代码(无 TaskSeq),发布版本,不附加调试器,则根本不会发生冻结(或者是察觉不到的)。

© www.soinside.com 2019 - 2024. All rights reserved.