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 实现上编译。
推荐阅读
- python-3.x - Django 模型约束或业务逻辑
- reactjs - REACT 应用程序调用安全的 Azure WEBAPI 服务 - 没有用户
- java - 有没有办法通过编码从安卓手机中提取浏览器历史记录?
- ruby-on-rails - 在运行 Ruby on Rails 项目时,按照以下格式出现错误
- bash - 在 Windows 上为 Git Bash 设置 .bashrc 时,为什么 PS1 中的函数显示函数名称而不是求值?
- activerecord - rspec中没有方法名时如何跳过回调的方法?
- azure-cosmosdb - 没有属性名称的嵌套数组上的 Cosmos DB SQL
- asp.net - ASP.Net 表单身份验证 - 5-10 分钟后登录超时
- variables - MuleSoft 运行时属性
- security - rclone --ignore-existing 会防止勒索软件损坏吗?