【问题标题】:Context Switches on Sleeping/Waiting Threads睡眠/等待线程上的上下文切换
【发布时间】:2015-04-08 14:52:09
【问题描述】:

我试图了解操作系统如何处理不同模型中的上下文切换,以更好地理解为什么 NIO 性能在请求数量达到较大峰值的情况下会更好。除了线程数量可能有限制之外,我很好奇在大量请求中执行的阻塞操作如何影响资源利用率。

在每个线程一个请求的模型中,比如基于 servlet 2.5 的 Web 应用程序,如果 499 个线程正在等待数据库 IO 并且只有一个线程需要工作,操作系统上下文是否会在所有这 500 个线程之间切换,试图找到那个那需要工作吗?为了执行上下文切换,操作系统必须存储当前线程的状态,并恢复下一个线程的状态。这样做之后,操作系统会发现它不需要任何 CPU 时间,并且会保持上下文切换,直到找到需要工作的线程。 此外,这在服务器利用率方面是什么样的? CPU 是否低,因为它主要受交换上下文的 IO 成本的限制,而不是实际计算任何东西?

提前感谢您的帮助。如果您能指出书籍、教科书等的方向,我也将不胜感激。

【问题讨论】:

  • 核心上的 CPU 执行是操作系统管理的资源之一。操作系统内核状态机已经知道哪些线程需要该资源,哪些不需要。如果一个线程请求 I/O 并且请求不能立即得到满足,操作系统知道该线程不需要 CPU 资源,直到 I/O 请求得到满足,所以它不会给线程任何执行,直到它满足.杰里米的回答有更多细节。

标签: multithreading threadpool nonblocking context-switch context-switching


【解决方案1】:

如果有 499 个线程在等待数据库 IO 并且只有一个线程需要 工作,操作系统上下文是否在所有这 500 个线程之间切换 试图找到需要工作的那个?

如果操作系统的调度程序设计合理,则不会;一直迭代系统的所有线程会非常低效。

相反,大多数调度程序实现都会保留一个睡眠/阻塞线程列表和一个单独的“准备运行”线程列表。当发生应该唤醒线程的事件时(例如,传入数据在套接字或文件句柄上变得可用,或者线程被阻塞的互斥锁被释放),操作系统将该线程从睡眠/阻塞-线程列表到就绪线程列表。然后,当需要执行上下文切换时,操作系统从就绪线程列表中选择一个线程,加载该线程的上下文,并开始运行它。在任何现代/流行的操作系统中,睡眠/阻塞线程列表的大小对调度程序从就绪线程列表中选择一个线程运行所需的时间完全没有影响。 (在某些操作系统下,就绪线程列表的大小可能会产生影响,但 some schedulers 的设计使得即使具有许多就绪线程的系统也不会导致调度程序效率降低)

CPU 是否低,因为它主要受交换的 IO 成本的限制 上下文进出,而不是实际计算任何东西?

假设您没有用完 RAM,则切换线程上下文不涉及 I/O;上下文切换仅涉及 CPU 和 RAM。如果 CPU 使用率低,最可能的原因是您的线程算法本身受 I/O 限制(例如,大多数情况下,大部分时间都在等待您的网卡或硬盘驱动器读取或写入数据)。如果您的线程实际上没有执行任何 I/O,并且您仍然受 I/O 限制,这可能表明您的计算机已用完其所有可用 RAM 并且是 thrashing - 不是一个好的状态进入。

【讨论】:

  • 好吧,“当发生应该唤醒线程的事件时”通常是“执行上下文切换的时间”。这种线程不会“立即”在内核上运行的唯一原因是所有内核当前都在运行高优先级线程。
  • 没错,但我试图让我的描述保持一般性。 (作为一个反例,请注意,在两个线程都设置为相同优先级的单核处理器上,上下文切换通常不会发生,直到第一个线程阻塞在某事上或其时间片到期)
  • ...即使没有 O(1) 调度程序,您通常也会为就绪线程使用优先级队列。那是 O(log N),因此就绪线程的数量通常仍然无关紧要,除非它变得非常庞大(这在大多数系统中是非常不寻常的)。就绪线程的数量通常足够小,以至于 O(1) 调度程序不一定优越。
猜你喜欢
  • 1970-01-01
  • 2017-07-02
  • 1970-01-01
  • 2013-05-29
  • 2021-11-18
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多