让线程休眠(C pthreads)

3

我正在使用 pthreads 并尝试让一个线程睡眠 X 秒。

我已经尝试过 sleep(), nanosleep(), pthread_cond_timedwait()(在一个虚假的互斥锁上等待 X 秒),pthread_yield(),每次线程唤醒时检查时间,以查看是否该运行,最后只是忙等待 X 秒。

问题是,尽管所有这些方法在结果方面都很好,但它们并没有给出我所期望的性能结果。性能是以吞吐量(每秒回复数)而不是时间来衡量的。

在我的配置中,我在 2 个模拟物理核心上运行了 3 个软件线程(VirtualBox 运行 Ubuntu Server)。当我让其中的 1 个线程睡眠时,我希望能获得更好的性能,因为其他 2 个线程有一个专用的 物理 核心可以运行。然而,我得到了完全相反的结果(使用所有方法):增加睡眠时间会导致性能变差。(请注意,睡眠 线程的工作量为 130-300ms。)

这可能是由于虚拟化(主机机器有 4 个核心)吗?这可能是因为我使用的方法与使用 pthread_yield 的方法类似吗?

sleep()nanosleep() 是如何实现的?它们使用信号吗?您认为使用信号处理程序和 alarm() 实现会是更好的方法吗?当我调用 pthread_cond_wait() 时会发生什么?它是如何实现的?

我还尝试使用 chrt 更改调度策略,但没有成功。


1
请您提供示例代码以及实际的性能数据(例如从 time 命令中获取),以便演示您的问题。 - Jay Sullivan
@Jarry 我应该如何持有互斥锁或信号量达 X 秒钟?你能给一个你所想的例子吗? - zakkak
@notfed,你可以在这里找到代码:http://code.google.com/p/lb-bind/source/browse/trunk/bind-9.9.0/bin/named/profiler.c#130。关于时间测量,性能是通过吞吐量而不是时间来衡量的 :) - zakkak
4
抱歉,但是在你的问题中没有定义“performance”和“results”的具体含义。在你明确测量绩效的精确指标之前,“如何提高绩效”的问题无法得到真正的回答。请先定义测量绩效的确切数量。 - chetan
性能是通过服务器(BIND)每秒回复的数量(吞吐量)来衡量的。通过将额外的线程(不处理请求)置于休眠状态,我希望其他两个线程能够运行更长时间并处理更多的请求。 - zakkak
显示剩余4条评论
2个回答

3
我同意@Aaron Digulla的观点,即通过反复试错和猜测永远无法回答性能问题。但更重要的是,根据您声称的睡眠时间越长,周期线程之间的吞吐量就越差,我不确定您是否在衡量正确的事物。按照这种逻辑,您可以将睡眠周期设置为无限大的数字(基本上大于您的测量周期),您的吞吐量应该是最差的。是这种情况吗?
请注意,测量服务器吞吐量可能是一个棘手的问题,受到许多测量和客户端设置中的陷阱的影响。以下是一些示例,说明您的合成基准数字有多容易被欺骗:http://www.teamquest.com/pdfs/whitepaper/load-test.pdf 如果您对性能测量感兴趣,请阅读该文章。它是纯金。

是的,情况就是这样。现在关于测量,我对我的测量技术很有信心,尽管我不是服务器方面的专家。我也会阅读您提供的参考资料,看看是否有任何可能与我的情况相关的内容,并希望像您所说的那样受益。 :) - zakkak
如果是这样的话,我认为你需要开始减少变量。你能在一个真正的物理多核机器上运行相同的测试吗(这样虚拟机的因素就不会影响结果了)?另外,增加工作线程的数量也是值得尝试的,看看它对吞吐量的影响如何。 - chetan
不幸的是,在物理多核上运行是不可能的,也是不可取的。我觉得玩弄线程数量是一个非常好的主意,不知道为什么我还没有尝试过。如果有任何有趣的事情发生,我会让你知道的。 - zakkak
实际上,增加软件线程的数量(4-8)确实隐藏了差异(将较长休眠的最低数字提高到与完全不休眠相同)。然而,该应用程序仍然无法从休眠线程中受益。同时,增加更多的线程也没有帮助,如果线程数足够大,它开始给出初始图像。 - zakkak
因此,如果不详细检查代码,我认为您的睡眠线程实际上正在做一些有用的工作,有助于吞吐量(除了定期的簿记类型工作之外)。而且可能存在一些阻塞操作(从磁盘/网络读取等),这意味着您需要比num_cpus更多的线程来保持CPU忙碌。 - chetan
当线程进入睡眠状态时,没有挂起的阻塞操作。此外,该线程对吞吐量没有任何贡献。其他线程确实在使用网络,这可能是为什么使用更多线程比核心表现更好的原因。然而,BIND的文档没有提到任何相关内容。它请求核心数,然后创建n+4个软件线程。 - zakkak

1
  1. 通过分析器运行您的代码,以查看时间花在哪里。否则,您只会猜测,根据我的经验,这些猜测90%是错误的。

  2. alarm()可能有所帮助,但它实际上应该做sleep()的工作,因此我不会真正期望有什么区别。

以下是可能导致此问题的一些想法:

  • 缓存刷新。如果您的两个工作线程非常好地使用缓存,则切换到新线程可能意味着缓存刷新,这可能非常昂贵。在这里,想法是如果休眠者让工作线程长时间保持空闲状态,则工作线程可以填充更多的缓存。

  • 两个工作线程需要一个由休眠者独占/锁定的资源。

  • 您如何衡量性能?也许您测量了其他效果(例如桌面搜索正在索引您的计算机等)

要彻底解决此问题,您必须逐个函数减少代码,直到出现所需的行为,并在分析器中运行它以检查意外情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接