在.Net native中的线程池上运行异步任务的性能很差

我发现托管vs .Net本机代码有一个奇怪的区别。 我有一个繁重的工作重定向到线程池。 当在托管代码中运行应用程序时,一切都运行顺畅,但是一旦我打开本机编译 – 任务运行速度慢几十倍,以至于它挂起UI线程(我猜CPU是如此过载)。

以下是调试输出的两个屏幕截图,左侧的屏幕截图来自托管代码,右侧的屏幕截图来自本机编译。 正如您所看到的,UI任务所消耗的时间在两种情况下几乎相同,直到启动线程池作业时 – 然后在托管版本中UI经过的时间增长(实际上UI被阻止而您无法采取任何操作)。 线程池工作的时间不言自明。

管理 本地人

重现问题的示例代码:

private int max = 2000; private async void UIJob_Click(object sender, RoutedEventArgs e) { IProgress progress = new Progress((p) => { MyProgressBar.Value = (double)p / max; }); await Task.Run(async () => { await SomeUIJob(progress); }); } private async Task SomeUIJob(IProgress progress) { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i  {watch.ElapsedMilliseconds}"); watch.Restart(); } await Task.Delay(1); progress.Report(i); } } private async void ThreadpoolJob_Click(object sender, RoutedEventArgs e) { Debug.WriteLine("Firing on Threadpool"); await Task.Run(() => { double a = 0.314; Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i  a value = {a} got in {watch.ElapsedMilliseconds} ms"); watch.Restart(); }; } }); Debug.WriteLine("Finished with Threadpool"); } 

如果您需要完整的样本 – 那么您可以在此处下载 。

正如我测试的那样,在优化/非优化代码中,在调试和发布版本中都会出现差异。

有没有人知道什么会导致这个问题?

导致此问题的原因是“ThreadPool”数学循环导致GC饥饿。 从本质上讲,GC已经决定它需要运行(由于想要进行一些互操作分配)并且它试图阻止所有线程进行收集/压缩。 不幸的是,我们还没有添加.NET Native能够劫持热循环的能力,就像你下面的那样。 有关将Windowsapp store应用迁移到.NET Native页面的简要说明如下:

无需在任何线程上进行调用(例如,while(true);)的无限循环可能会使应用程序停止。 同样,大量或无限等待可能会使应用程序停止运行。

解决此问题的一种方法是在循环中添加一个调用站点(GC非常乐意在尝试调用另一个方法时中断您的线程!)。

  for (long i = 0; i < 5000000000; i++) { MaybeGCMeHere(); // new callsite a = Math.Sqrt(a) + Math.Sqrt(a + 1) + i; if (i % 1000000000 == 0) { Debug.WriteLine($"Threadpool -> a value = {a} got in {watch.ElapsedMilliseconds} ms"); watch.Restart(); }; } ... [MethodImpl(MethodImplOptions.NoInlining)] // need this so the callsite isn't optimized away private void MaybeGCMeHere() { } 

缺点是你会有这种“丑陋”的黑客攻击,你可能会受到添加指令的影响。 我让这里的一些人知道,我们认为这种“消失罕见”的事实上是由客户打击,我们会看到可以做些什么。

谢谢你的报道!

更新:我们围绕这种情况做了一些重大改进,并且能够劫持大多数长期运行的GC线程。 这些修复程序可能会在4月份的Update 2 UWP工具集中提供吗? (我不控制出货时间表:-))

更新更新:新工具现已作为UWP工具1.3.1的一部分提供。 我们不希望有一个完美的解决方案来积极地反对被GC劫持的线程,但我希望使用最新的工具可以更好地利用这种情况。 让我们知道!