我使用boost spsc_queue
将我的东西从一个线程移动到另一个线程。它是我软件中的关键位置之一,所以我希望尽快完成。我写了这个测试程序:
#include <boost/lockfree/spsc_queue.hpp>
#include <stdint.h>
#include <condition_variable>
#include <thread>
const int N_TESTS = 1000;
int results[N_TESTS];
boost::lockfree::spsc_queue<int64_t, boost::lockfree::capacity<1024>> testQueue;
using std::chrono::nanoseconds;
using std::chrono::duration_cast;
int totalQueueNano(0);
int totalQueueCount(0);
void Consumer() {
int i = 0;
int64_t scheduledAt;
while (i < N_TESTS - 1) {
while (testQueue.pop(scheduledAt)) {
int64_t dequeuedAt = (duration_cast<nanoseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())).count();
auto diff = dequeuedAt - scheduledAt;
totalQueueNano += diff;
++totalQueueCount;
results[i] = diff;
++i;
}
}
for (int i = 0; i < N_TESTS; i++) {
printf("%d ", results[i]);
}
printf("\nspsc_queue latency average nano = %d\n", totalQueueNano / totalQueueCount);
}
int main() {
std::thread t(Consumer);
usleep(1000000);
for (int i = 0; i < N_TESTS; i++) {
usleep(1000);
int64_t scheduledAt = (duration_cast<nanoseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())).count();
testQueue.push(scheduledAt);
}
usleep(1000000);
return 0;
}
编译标志:
g++ -std=c++0x -O3 -Wall -c -fmessage-length=0 -march=native -mtune=native -pthread -MMD -MP -MF"src/TestProject.d" -MT"src/TestProject.d" -o "src/TestProject.o" "../src/TestProject.cpp"
g++ -pthread -o "TestProject" ./src/TestProject.o -lpthread
在我的机器上:RHEL 7.1,gcc 4.8.3,Xeon E5-2690 v3我收到290-300纳秒。
upd:队列机制。如果第一个线程每1000纳秒产生一次数据,但第二个线程花费10 000纳秒来处理我需要的单个项目&#34; queue&#34;短时间内的几个项目。但我的排队&#34;从来没有&#34;太大&#34;。固定大小的短环缓冲区必须足够。
upd2 所以简而言之,问题是 - 什么是最快的单一生产者单一消费者队列(最有可能基于固定大小的环形缓冲区)?我使用boost spsc_queue并且达到~300 ns的延迟,你能更快地提出建议吗?
java世界中的 upd3 有一个干扰器可以实现50 ns的延迟https://code.google.com/p/disruptor/wiki/PerformanceResults我们在c ++中有一些具有相同50 ns延迟的东西吗?答案 0 :(得分:6)
由于您有int
s,所以您(理想情况下)衡量的是调用push()
到pop()
返回true
之间的整体延迟。
这没有意义:消费者线程忙于轮询队列,即循环并忙着检查pop
是否已获取价值。
如果(IFF)你希望最小化延迟(对于单个项目),我的 guess 将使用信令同步机制spsc_queue
,据我所知,没有规定这个。 (您需要一个容器或自定义解决方案,您需要使用condition variable /事件,...)
但是,如果(IFF),您希望最大化吞吐量(每次的项目数),那么测量&#34;唤醒的延迟&#34;一个(单个)项目确实没有意义。在这种情况下,您希望充分利用您拥有的并行性,如is mentioned in a comment:
传递数据的最快方法通常是为每个数据块使用一个线程。也就是说,只使用数据中存在的并行性。
解决你的要点:
测试应用程序有多好:我觉得它没有多大意义。
scheduledAt
。否则你有UB。struct {int val; int64_t time; };
放入队列,从而避免使用原子围栏。当前行业最佳时间:没有头绪。不确定是否有人关心这一点。 (也许在某些内核中?)
选择spsc_queue :我认为这不是一个好选择,因为它需要投票。
比spsc_queue更快?:见上文。使用非投票通知。
编写一个代码,可以更快地完成相同的工作吗?:不。或者更确切地说,我不会。 =&GT;
- 您定义问题并选择适当的同步机制
醇>
您的问题是没有问题定义。
到目前为止,我担心在常规操作系统上的用户登陆过程中,跨线程通知延迟似乎完全无关紧要。 您的用例是什么?
答案 1 :(得分:2)
首先,编写这样的测试程序是完全没用的。您不对数据进行任何处理,因此结果会有所偏差。其次,您的测试是在推送之间使用usleep() - 以此速率,您可以使用任何类型的同步原语。 你的消费者()似乎也永远不会退出...
您实现此类事情的方式如下:
您在第一步需要一些以前的经验,或者您可以尝试实施不同的方法,看看什么效果最好。
答案 2 :(得分:0)
它取决于应用程序的语义以及涉及的线程数。到目前为止,您正在研究原始延迟。使用更多线程,扩展也可能开始成为一个有趣的指标。
对于双线程情况,如果您对检索到的数据执行的操作,对单个位置(最好是在任何其他操作未触及的缓存行中)的原子更新可能会更快允许它。