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

2024-05-15

我正在使用增强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 纳秒。

  • 我的测试应用程序有多好?我是否正确测量了“spsc_queue”延迟?
  • 目前业界将数据从一个线程传递到另一个线程的最佳时间是什么?
  • 使用 boost spsc_queue 将数据从一个线程移动到另一个线程是一个好的选择吗?
  • 你能推荐一些比 spsc_queue 更快的东西吗?
  • 你能编写一段代码来显着更快地完成相同的工作吗?

upd:需要队列机制。如果第一个线程每 1000 纳秒生成一次数据,但第二个线程花费 10 000 纳秒来处理单个项目,我需要在短时间内“排队”多个项目。但我的“队列”从来都不是“太大”。固定大小的短环形缓冲区必须足够。

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

upd3在 Java 世界中,有一种 Disruptor 可以实现 50 ns 延迟https://code.google.com/p/disruptor/wiki/PerformanceResults https://code.google.com/p/disruptor/wiki/PerformanceResults我们在 C++ 中是否有具有相同 50 ns 延迟的东西?


既然你有ints,您(理想情况下)上面测量的是调用之间的总体延迟push()到时间pop()回报true.

这没有道理: 消费者线程繁忙polling队列,即循环并忙于检查是否pop已获取一个值。

  • 这是浪费,而且
  • 如果你想最小化延迟,轮询肯定是not要走的路

如果(IFF)您想最大限度地减少延迟(对于单个项目),我的guess将使用信令同步机制,spsc_queue http://www.boost.org/doc/libs/1_57_0/doc/html/boost/lockfree/spsc_queue.html#idp161977984-bb据我所知,没有对此做出规定。 (您需要一个容器或自定义解决方案,在其中使用一种条件变量 http://www.boost.org/doc/libs/1_57_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref.condition_variable/ 事件, ...)

但是,如果 (IFF) 您希望最大化吞吐量(每次的项目数),那么测量(单个)项目“唤醒”的延迟就更没有意义了。在这种情况下,您希望充分利用所拥有的并行性,例如评论中提到 https://stackoverflow.com/questions/29507669/fastest-possible-way-to-pass-data-from-one-thread-to-another?noredirect=1#comment47172171_29507669:

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


解决您的要点:

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

    • Having scheduledAt原子是必需的,因为您从一个线程写入它并从另一个线程读取它。否则你就有UB了。
    • 显然任何测量差异。这纯粹是一个测量误差,并没有说明固有延迟。 (您可以尝试将总计struct {int val; int64_t time; };进入队列,从而避开原子栅栏。
  • 当前行业最佳时机: 没有线索。不确定是否有人关心这个。 (也许在一些内核的东西里面?)

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

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

  • 编写一段代码,其执行相同工作的速度明显更快?:不。或者更确切地说,我不会。 =>

去引用“男人”的回答 https://stackoverflow.com/a/29508216/321013:

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

你的问题的问题在于没有问题定义.

到目前为止,就我而言,在常规操作系统上的用户态进程的上下文中,跨线程通知延迟似乎完全无关紧要。您的用例是什么?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将数据从一个线程传递到另一个线程的最快可能方法 的相关文章

  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • iPhone SDK - 在后台线程中运行重复进程

    我有一个iPhone我想在其中每隔一段时间在后台执行一个方法的应用程序1第二 所以在我的主线程中 我有以下代码UIViewController viewDidLoad NSTimer timerWithTimeInterval 1 0 ta
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 为什么 POSIX 允许在只读模式下超出现有文件结尾 (fseek) 进行搜索

    为什么寻找文件结尾很有用 为什么 POSIX 让我们像示例中那样在以只读方式打开的文件中进行查找 c http en cppreference com w c io fseek http en cppreference com w c io
  • 为什么禁止在 constexpr 函数中使用 goto?

    C 14 对你能做什么和不能做什么有规则constexpr功能 其中一些 没有asm 没有静态变量 看起来相当合理 但标准也不允许goto in constexpr功能 即使它允许其他控制流机制 这种区别背后的原因是什么 我以为我们已经过去
  • 写入和读取文本文件 - C# Windows 通用平台应用程序 Windows 10

    有用 但在显示任何内容之前 您必须在文本框中输入内容 我想那是因为我使用了 TextChanged 事件处理程序 如果我希望它在没有用户交互的情况下显示文本文件的内容 我应该使用哪个事件处理程序 因此 我想在按下按钮时将一些数据写入 C W
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • 如何在 Team Foundation 上强制发表有意义的签入评论?

    我有一个开发团队有一个坏习惯 他们写道poor签入评论 当我们必须在团队基础上查看文件的历史记录时 这使得它成为一场噩梦 我已经启用了变更集评论政策 这样他们甚至可以在签到时留下评论 否则他们不会 我们就团队的工作质量进行了一些讨论 他们很
  • 是否有比 lex/flex 更好(更现代)的工具来生成 C++ 分词器?

    我最近将源文件解析添加到现有工具中 该工具从复杂的命令行参数生成输出文件 命令行参数变得如此复杂 以至于我们开始允许它们作为一个文件提供 该文件被解析为一个非常大的命令行 但语法仍然很尴尬 因此我添加了使用更合理的语法解析源文件的功能 我使
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • 更改窗口的内容 (WPF)

    我创建了一个简单的 WPF 应用程序 它有两个 Windows 用户在第一个窗口中填写一些信息 然后单击 确定 这会将他们带到第二个窗口 这工作正常 但我试图将两个窗口合并到一个窗口中 这样只是内容发生了变化 我设法找到了这个更改窗口内容时
  • 将应用程序从 Microsoft Access 迁移到 VB 或 C#.NET

    我目前正试图说服管理层需要将我们的应用程序之一移植到 NET 该应用程序已经发展成为 Access 中的一个庞然大物 SQL 后端 拥有 700 个链接表 650 个表单 子表单 130 个模块和 850 个查询 我几乎知道这样做的所有主要
  • 作为字符串的动态属性名称

    使用 DocumentDB 创建新文档时 我想设置属性名称动态地 目前我设置SomeProperty 像这样 await client CreateDocumentAsync dbs db colls x new SomeProperty
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的
  • 为什么这个函数在额外读取内存时运行速度如此之快?

    我目前正在尝试了解 x86 64 上某些循环的性能属性 特别是我的 Intel R Core TM i3 8145U CPU 2 10GHz 处理器 具体来说 在循环体内添加一条额外的指令来读取内存几乎可以使性能提高一倍 而细节并不是特别重

随机推荐