减少具有相同优先级的线程之间的上下文切换

Reduce Context Switches Between Threads With Same Priority

本文关键字:线程 之间 上下文切换 优先级      更新时间:2023-10-16

我正在编写一个使用第三方库执行繁重计算的应用程序。

这个库在内部实现并行,并生成给定数量的线程。我想运行这个库的几个(动态计数)实例,因此最终会严重超额订阅cpu。

有没有什么方法可以增加进程中所有线程的"时间量",例如,所有具有正常优先级的线程很少切换上下文(yield),除非它们是通过例如信号量显式生成的?

这样,我就可以避免过度订阅cpu带来的大部分性能开销。请注意,在这种情况下,我不在乎线程是否会被饿死几秒钟。

编辑:

一种复杂的方法是手动执行线程调度。

  1. 枚举具有特定优先级的所有线程(例如普通线程)
  2. 暂停所有操作
  3. 创建一个循环,每隔40ms恢复/挂起线程,并确保运行的线程数不超过当前cpu数

这种方法有什么主要缺点吗?不确定恢复/挂起线程的开销是多少?

没有什么特别的事情需要做。任何像样的调度程序都不会允许非强制上下文切换占用很大一部分CPU资源。任何没有合适调度程序的操作系统都不应该使用。

超额预订CPU的性能开销是,而不是非强制上下文切换的成本。为什么?因为调度器可以简单地避免这些。调度程序只在有好处的情况下执行非强制上下文切换。性能成本为:

  1. 完成一项作业可能需要更长的时间,因为从作业开始到作业完成,其他作业将完成更多的工作。

  2. 额外的线程为其堆栈和相关的其他跟踪信息消耗内存。

  3. 更多的线程通常意味着更多的争用(例如,当分配内存时),这可能意味着更多强制的上下文切换,因为线程无法向前推进,所以必须切换。

您只想在知道调度程序不知道的重要内容时尝试更改调度程序的行为。这里没有发生这样的事。所以默认行为就是你想要的。

这种方法有什么主要缺点吗?不确定的开销是多少恢复/挂起线程是什么?

,恢复/挂起线程是在程序的用户模式下进行的非常非常危险的活动。因此,它不应该被使用(几乎永远不会)。此外,我们不应该用这些概念来实现任何现代调度器为我们所做的事情。这个问题的其他帖子也提到了这一点。

上面的内容适用于任何操作系统,但从SO post标签来看,我似乎已经被要求使用基于Microsoft Windows的系统。现在,如果我们阅读MSDN中的SuspendThread(),我们会得到以下内容:

"此函数主要设计用于调试器。不打算用于线程同步。如果调用线程试图获得挂起线程所拥有的同步对象,如互斥对象或关键节,则在拥有同步对象的线程上调用SuspendThread会导致死锁"。

因此,考虑线程已经获取了一些资源的场景(通过库或内核模式隐式地,即非代码的一部分),如果我们挂起线程,这将导致神秘的死锁情况,因为该进程的其他线程将等待该特定资源。事实上,我们不确定(在任何时候)在我们的程序中,任何正在运行的线程获取什么样的资源,挂起/恢复线程都不是一个好主意。