将数据从一个线程传递到另一个线程的最快方法

jav*_*red 8 c++ performance multithreading boost lock-free

我正在使用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;
}
Run Code Online (Sandbox Code Playgroud)

编译标志:

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
Run Code Online (Sandbox Code Playgroud)

在我的机器上:RHEL 7.1,gcc 4.8.3,Xeon E5-2690 v3我收到290-300纳秒.

  • 我的测试应用程序有多好?我是否正确测量"spsc_queue"延迟?
  • 什么是当前行业最佳时间将数据从一个线程传递到另一个线程?
  • 使用boost spsc_queue将数据从一个线程移动到另一个线程是否是一个不错的选择?
  • 你能推荐比spsc_queue更快的东西吗?
  • 你能编写一个能快得多地完成同样工作的代码吗?

upd:队列机制是必需的.如果第一个线程每1000纳秒产生一次数据,但是第二个线程花费10000纳秒来处理单个项目,我需要在短时间内"排队"几个项目.但我的"队列"永远不会"太大".固定大小的短环缓冲区必须足够.

upd2简而言之,问题是 - 什么是最快的单一生产者单一消费者队列(最有可能基于固定大小的环形缓冲区)?我正在使用boost spsc_queue并且我实现了~300 ns的延迟,你能建议更快的东西吗?

java世界中的upd3有一个破坏者可以实现50 ns的延迟https://code.google.com/p/disruptor/wiki/PerformanceResults我们在c ++中有一些具有相同50 ns延迟的东西吗?

Mar*_* Ba 6

由于你有ints,你(理想情况下)测量的是调用push()时间pop()返回之间的总延迟true.

这没有意义:消费者线程忙于轮询队列,即循环并忙于检查是否pop已获取值.

  • 这很浪费,而且
  • 如果你想最大限度地减少延迟,轮询肯定不是可行的方法

如果(IFF)你想最小化延迟(对于单个项目),我的猜测是使用信令同步机制,spsc_queue据我所知,没有提供这一点.(你需要一个容器或自定义解决方案,你使用一种条件变量 /事件,......)

但是,如果(IFF),您想要最大化吞吐量(每次的项目),那么测量(单个)项目的"唤醒"的延迟确实更没意义.在这种情况下,您希望充分利用您所拥有的并行性,如评论中所述:

通常,传递数据的最快方法是为每个数据块使用单个线程.也就是说,仅使用数据中存在的并行性.


解决你的要点:

  • 测试应用程序有多好:我认为它没有多大意义.

    • scheduledAt当你从一个线程写入并从另一个线程读取它时,需要有一个原子.否则你有UB.
    • 显然任何测量差异都可以.这纯粹是一个测量误差,并没有说明固有的延迟.(您可以尝试将聚合struct {int val; int64_t time; };放入队列,从而避免原子围栏.
  • 当前行业最佳时间:没有头绪.不确定是否有人关心这一点.(也许在某些内核中?)

  • 选择spsc_queue:我认为这不是一个好选择,因为它需要轮询.

  • 比spsc_queue更快?: 往上看.使用非轮询通知.

  • 编写一个代码,可以更快地完成相同的工作?:不,或者说,我不会.=>

引用"男人"的回答:

  1. 您定义问题并选择适当的同步机制

您的问题的问题是没有问题定义.

到目前为止,我担心在常规操作系统上的用户登陆过程中,跨线程通知延迟似乎完全无关紧要.你的用例是什么?


小智 2

首先,写这样的测试程序是完全没有用的。您没有对数据进行任何处理,因此结果存在偏差。其次,您的测试在推送之间使用 usleep() - 以这种速度您可以使用任何类型的同步原语。看来你的 Consumer() 永远不会退出......

实现这样的事情的方式如下:

  1. 您定义问题并选择适当的同步机制
  2. 您实施该软件
  3. 您对软件进行分析以识别潜在的热点
  4. 您根据上一步的结果进行优化并重复。

第一步您需要一些先前的经验,或者您可以尝试实施不同的方法,看看哪种方法最有效。