C语言 以亚微秒频率同步线程和测量性能的最佳方式



我正在研究标准的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 年龄百分比在噪音级别下降......或者至少探查器是这么说的。 他们一定在做点什么,否则我看不到任何速度!

我可以并且做计时的事情,但很难区分生产者线程中磁盘延迟带来的延迟和线程同步时花费的延迟。

那么有没有更好的方法来衡量实际情况呢? 我的意思是这些线程真正花费了多少时间等待彼此? 在亚微秒分辨率下准确测量时间真的很难,分析器似乎没有给我太多帮助,我正在努力优化方案。

或者也许我的自旋等待方案是垃圾,但我似乎找不到更好的亚微秒同步解决方案。

任何提示都会受到欢迎:-(

比快速锁更好的是根本不锁定。尝试切换到无锁队列。生产者和消费者根本不需要等待。

无锁数据结构是进程、线程和中断安全的(

即相同的数据结构实例可以安全地跨内核、进程、线程以及中断处理程序内部和外部同时使用(、永不休眠(因此在不允许休眠时对内核使用是安全的(、在没有上下文切换的情况下运行、不会失败(无需处理错误情况, 因为没有(,执行和扩展比锁定数据结构好几个数量级,liblfds 本身(从版本 7.0.0 开始(的实现使得它不执行分配(因此适用于 NUMA、堆栈、堆和共享内存(,并且不仅在独立的 C89 实现上编译,而且在裸 C89 实现上编译。

感谢上面所有评论的人,使工作量更大的建议是关键。 我现在已经为我的使用者线程实现了一个队列(1000 个条目长旋转缓冲区(,因此生产者只需要等待该队列已满,而不是在我以前的方案中等待其双缓冲区的一半。所以它的同步时间现在是亚毫秒而不是亚微秒 - 这是一个猜测,但它肯定比以前长 1000 倍!

如果生产者达到"队列已满",我现在可以立即产生它的线程,而不是等待旋转,因为知道它丢失的任何时间片都将被消费者线程有益地使用。 这确实在探查器中显示为少量的睡眠/旋转时间。使用者线程也从中受益,因为它们具有更均匀的工作负载。

最终结果是读取文件的总时间减少了 10%,并且考虑到只有文件的一部分能够以线程方式处理,这表明该过程的线程部分快了大约 15% 或更多。

最新更新