在使用Vtune分析程序时,我看到libc
函数sched_yield
被标记为重要热点。
现在我看到这个函数大致负责上下文切换;我说大致是因为这是我第一次遇到这个函数,所以我的理解是它在操作系统调度器中运行,为更改活动线程提供支持。
将sched_yield
作为主要热点对我的程序意味着什么?这是否意味着我创建了比我应该创建的更多的线程,并且操作系统正在试图处理连续的上下文切换?
这种情况的补救办法是什么?也许诉诸更集中的线程池,以避免过度产卵的线程?
接下来我应该分析什么?有"典型的"吗?在这种情况下,下一步是什么?Vtune已经建议对"threading"进行分析。
将
sched_yield
作为主要热点对我的程序意味着什么?
在Linux上,sched_yield
不需要切换到另一个线程来执行。如果在同一个CPU上没有准备好运行的线程,内核不会取消调用线程的调度。最后一部分很重要,因为内核不会在此调用时在cpu之间重新调度准备运行的线程。这是一个设计权衡,因为sched_yield
应该是一个低成本的内核提示。
由于sched_yield
可能只是立即返回而不做任何事情,您的代码可能在此调用周围有一个繁忙的循环,这将看起来像您的配置文件中的热点。你的代码只是在sched_yield
周围循环了很多,没有做其他的事情。这样的旋转会消耗大量的CPU周期,而这些CPU周期本可以用于系统上运行的其他线程和应用程序。
这种情况的补救措施是什么?
这在很大程度上取决于您的用例。当您愿意浪费一些CPU周期以换取更好的延迟时,使用sched_yield
可能是可以接受的。您必须意识到这个决定,即使这样,我也会建议您对具有适当线程阻塞的不同解决方案进行基准测试。Linux线程调度器非常高效,所以阻塞和唤醒线程不像在其他系统上那么昂贵。
通常在自定义自旋锁算法中使用sched_yield
。我建议用pthread组件替换它们,特别是pthread_cond_t
,它允许正确地阻塞和唤醒线程。如果你使用的是c++,在标准库中也有相应的函数(例如std::condition_variable
)。在其他情况下,可能值得探索其他阻塞api,例如select
和epoll。确切的解决方案取决于您的用例。