索引方式(字节方式?)锁定/原子添加到 std::vector 或 Eigen::Array 中?

发布于 2025-01-09 13:42:42 字数 1659 浏览 2 评论 0原文

我需要计算然后将值添加到 Eigen::ArrayXd (双精度数组)。因为这个操作需要很长时间,所以我把这个工作分成了多个线程。由于问题的性质,大多数时候线程会添加到彼此不同的索引。 (通常,与整个数组相比,该问题相对稀疏)

但是,这引发了多个线程尝试同时添加到同一索引的明显问题。

我知道有两种方法可以处理这个问题:

  • 为每个线程提供最终特征数组的自己的副本,并对它们求和 一起。这对性能有好处,但可以使用令人难以置信的 大量的内存来解决我的问题。 (几千兆字节是很有可能的)
  • 给每个线程一个更紧凑的结构(就像一个 std::unordered_map) 仅包含索引 进行了手术。这使用的内存少得多,但开销 最后的加法是如此之大,以至于最终几乎完全无效 多线程的改进。

第一种方法的示例如下:

  unsigned numThreads = std::thread::hardware_concurrency();

  std::vector<Eigen::ArrayXd> threadData( numThreads );
  std::vector<std::thread> threads( numThreads );

  // This spools up new threads to perform the calculation
  if ( numThreads == 1 ) {
    threadData[0] = Eigen::ArrayXd::Zero( solutionArray.size() );
    calculateThread( 0, 1, threadData[0] );

    solutionArray += threadData[0];
  } else {
    // Start the threads
    for ( unsigned i = 0; i < numThreads; i++ ) {
      threadData[i] = Eigen::ArrayXd::Zero( solutionArray.size() );
      threads[i] = std::thread( &My_class::calculate,
        this,
        i,
        numThreads,
        std::ref( threadData[i] ) );
    }

    // Wait for all threads to finish
    for ( unsigned i = 0; i < numThreads; i++ ) {
      threads[i].join();
      const Eigen::ArrayXd &threadSol = threadData[i];

      // Add this thread's results into the final solution array
      solutionArray += threadSol;
    }
  }

这两种方法都不理想。有没有某种方法可以按字节锁定 std::vector 或 Eigen::ArrayXd ,以便多个线程可以访问并添加到数组中,而不会产生大量内存开销或缓慢的组合步骤?这样,唯一浪费的时间就是每当它们达到相同的索引时,这种情况相当罕见。

我询问 std::vector 因为将其转换为 Eigen 数组相对简单,所以如果没有 Eigen 等效项,我可以这样做。

I need to calculate and then add values to an Eigen::ArrayXd (array of doubles). Because this operation takes a long time, I have split this work amongst threads. Due to the nature of the problem, most of the time threads will be adding to different indices than each other. (and generally the problem is relatively sparse compared to the overall array)

However, this raises the obvious problem of multiple threads trying to add to the same index simultaneously.

There are 2 ways I know of to deal with this:

  • Give each thread its own copy of the final Eigen array, and sum them
    together. This is good for performance, but can use an incredibly
    large amount of memory for my problem. (Several gigabytes is very possible)
  • Give each thread a more compact structure (like a
    std::unordered_map<int, double>) containing just the indices it
    operated on. This is uses far less memory, but the overhead of the
    final addition is so large it ends up almost completely nullifying
    the multi-threaded improvement.

An example of the first approach is here:

  unsigned numThreads = std::thread::hardware_concurrency();

  std::vector<Eigen::ArrayXd> threadData( numThreads );
  std::vector<std::thread> threads( numThreads );

  // This spools up new threads to perform the calculation
  if ( numThreads == 1 ) {
    threadData[0] = Eigen::ArrayXd::Zero( solutionArray.size() );
    calculateThread( 0, 1, threadData[0] );

    solutionArray += threadData[0];
  } else {
    // Start the threads
    for ( unsigned i = 0; i < numThreads; i++ ) {
      threadData[i] = Eigen::ArrayXd::Zero( solutionArray.size() );
      threads[i] = std::thread( &My_class::calculate,
        this,
        i,
        numThreads,
        std::ref( threadData[i] ) );
    }

    // Wait for all threads to finish
    for ( unsigned i = 0; i < numThreads; i++ ) {
      threads[i].join();
      const Eigen::ArrayXd &threadSol = threadData[i];

      // Add this thread's results into the final solution array
      solutionArray += threadSol;
    }
  }

Neither of these are ideal. Is there some way to byte-wise lock a std::vector or Eigen::ArrayXd so that multiple threads can access and add to the array without a large memory overhead or slow combination step? That way the only wasted time is whenever they do hit the same index, which is fairly rare.

I ask about std::vector since it's relatively trivial to just convert one into an Eigen array, so if there is no Eigen equivalent I can do that instead.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文