我的工作是一个标准的x86六核SMP机器,3.6GHz时钟速度,普通C代码。
我有一个线程生产者/使用者方案,在这个方案中,我的“生产者”线程以大约1,000,000行/秒的速度从文件中读取数据,并将它读取的数据传递给两个或四个“使用者”线程,这些线程对其做一些工作,然后将其放入数据库中。当他们消费的时候,它正忙着读下一行。
因此,生产者和消费者都必须有一些在亚微秒频率下工作的同步手段,对此我使用“繁忙的自旋等待”循环,因为我能找到的所有正常的同步机制都太慢了。用伪码表示:
出厂线
While(something in file)
{
read a line
populate 1/2 of data double buffer
wait for consumers to idle
set some key data
set memory fence
swap buffers
}
消费者的线程也是如此。
while(not told to die)
{
wait for key data change event
consume data
}
在两边都对“等待”循环进行编码:
while(waiting)
{
_mm_pause(); /* Intel say this is a good hint to processor that this is a spin wait */
if(#iterations > 1000) yield_thread(); /* Sleep(0) on Windows, pthread_yield() on Linux */
}
这一切都能工作,而且与等效的串行代码相比,我得到了一些相当好的速度提升,但是我的分析器(英特尔的VTune放大器)显示,我在繁忙的等待循环中花费了可怕的时间,而“自旋”与“完成的有用工作”的比率令人沮丧地高。鉴于分析器将其反馈集中在最繁忙的部分上,这也意味着执行有用工作的代码行往往不被报告,因为(相对地说)它们在cpu总数中所占的百分比降低到了噪音水平。或者至少这就是分析人员所说的。他们一定在做些什么,否则我看不出任何提速!
我可以做时间方面的事情,但很难区分由生产者线程中的磁盘延迟造成的延迟和线程同步时所花费的延迟。
那么,有没有更好的方法来衡量到底发生了什么呢?我的意思是,这些线程到底要花多少时间等待对方呢?精确测量时间真的很难在亚微秒分辨率,轮廓仪似乎没有给我多少帮助,我正在努力优化方案。
或者我的旋转等待计划是垃圾,但我似乎找不到更好的解决方案,亚微秒同步。
任何暗示都会受到欢迎:-)
发布于 2019-10-08 11:00:11
甚至比快锁更好的是根本没有锁定。尝试切换到无锁队列。生产商和消费者根本不需要等待。
无锁的数据结构是进程、线程和中断安全的(即相同的数据结构实例可以安全地在内核、进程、线程以及中断处理程序的内部和外部同时使用),从不休眠(因此在不允许休眠时内核使用是安全的),在没有上下文开关的情况下进行操作,不能失败(不需要处理错误情况,因为没有),执行和缩放实际上比锁定数据结构更好,而且liblfds本身(发布7.0.0版)的实现使得它不执行任何分配(因此与NUMA、堆栈、(堆和共享内存),不仅在独立的C89实现上编译,而且在单独的C89实现上编译。
发布于 2019-10-09 09:43:36
感谢所有以上评论的人,让工作量更大的建议是关键。我现在已经为我的使用者线程实现了一个队列(1000个条目长的旋转缓冲区),所以生产者只能在队列满的情况下等待,而不是在我以前的方案中等待它一半的双缓冲区。所以它的同步时间现在是亚毫秒而不是亚微秒--这是一个推测,但它肯定比以前长了1000倍!
如果生产者点击“队列满”,我现在可以立即释放它的线程,而不是旋转等待,因为知道它丢失的任何时间片段都将被使用者线程有效地使用。这确实会在分析器中显示为少量的睡眠/旋转时间。使用者线程也从中受益,因为它们有更均匀的工作负载。
Net结果是读取文件的总时间减少了10%,并且考虑到只有部分文件能够以线程方式处理,这意味着进程的线程部分大约要快15%或更快。
https://stackoverflow.com/questions/58292230
复制相似问题