c++ - 中型对象连接和合并的 vector

标签 c++ performance

我有一个很simple program我在这里合并两个 100 字节对象的 vector (SortRecord)。

#include <numeric>
#include <iostream>
#include <sstream>
#include <array>
#include <chrono>

constexpr size_t TUPLE_SIZE = 90;
constexpr size_t KEY_SIZE = 10;
constexpr size_t TUPLE_COUNT = 1024 * 1024 * 20;
constexpr size_t ARRAY_COUNT = 2;

using Record = std::array<uint8_t, TUPLE_SIZE>;
using Header = std::array<uint8_t, KEY_SIZE>;
using TimerClock = std::chrono::system_clock;

struct SortRecord {
    Header header;
    Record record;

    bool operator<(const SortRecord& record)
    {
        const uint64_t a = *reinterpret_cast<const uint64_t*>(&header[0]);
        const uint64_t b = *reinterpret_cast<const uint64_t*>(&record.header[0]);

        if (a == b)
        {
            const uint16_t c = *reinterpret_cast<const uint16_t*>(&header[8]);
            const uint16_t d = *reinterpret_cast<const uint16_t*>(&record.header[8]);
            return c < d;
        }
        return a < b;
    }
};

template<size_t tuplecount>
static auto CreateArray()
{
    std::array<std::vector<SortRecord>, ARRAY_COUNT> data_array;
    uint64_t hvalue = 0;
    srand(100);

    for (auto& data : data_array)
    {
        data.resize(tuplecount);
        hvalue = 0;
        std::for_each(data.begin(), data.end(), [&hvalue](auto& it)
        {
            *reinterpret_cast<uint64_t*>(&it.header[0]) = hvalue = hvalue + (rand() % 100);
        });
    }

    return data_array;
}

auto data_array = CreateArray<TUPLE_COUNT>();

// merge
std::vector<SortRecord> result1;
result1.reserve(TUPLE_COUNT * 2);
auto start = TimerClock::now();
std::merge(data_array[0].begin(), data_array[0].end(),
    data_array[1].begin(), data_array[1].end(),
    std::back_inserter(result1));
auto end = TimerClock::now();
std::cout << std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()) << " [ms]\n";

我尝试将它与这两个 vector 的简单串联进行比较,令人惊讶的是它的速度几乎相同。

// concatenation
std::vector<SortRecord> result2;
result2.reserve(TUPLE_COUNT * 2);
auto start2 = TimerClock::now();
result2.insert(result2.end(), data_array[0].begin(), data_array[0].end());
result2.insert(result2.end(), data_array[1].begin(), data_array[1].end());  
auto end2 = TimerClock::now();
std::cout << std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2).count()) << " [ms]\n";

我已经在 MSVC 2017 和 gcc 上试过了并且结果非常相似。当我尝试将 SortRecord 替换为 float 或 int 时,突然间我得到了很多 better results用于串联。

SortRecord 变体有什么问题?

最佳答案

你基本上有两种效果,它们都与要合并的元素数量成线性比例:

  • 必须读取和写入元素
  • 此外merge必须比较元素

这两种贡献都与元素数量呈线性关系,但它们对元素大小的依赖性似乎不同。

int 插入与合并

对于较小的 int,由于比较元素而产生的开销占优,您会看到 insert 优于 merge

SortRecord 插入与合并

您的 SortRecord 相当庞大。在这种情况下,主要贡献似乎来自读写元素,比较它们只是次要贡献。 (我有点困惑,为什么在您的基准测试中 merge 实际上比 insert 快 10%,但让我们称之为微不足道;)。

可以推测它与缓存有关,而且内存访问实际上并不是线性扩展的。无论如何,如果你只是让 SortRecord 变小,但保持要合并的元素数量,你 see the same difference as for integers .

关于c++ - 中型对象连接和合并的 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55418949/

相关文章:

java - 更新ArrayList的最高性能方法

javascript - 重复的 gsap 动画代码和服务器加载时间

c++ - 虚函数性能: one large class vs many smaller subclasses

c++ - WM_KEYDOWN 消息未发送

C++ : The second time calling a function, 但仍然影响我以前的指针

c++ - QApplication::processEvents 在 Windows 中不工作

c++ - STL find 的性能优于手工循环

c++ - 修改 2D Array 的 malloc 策略,使 malloc 成功

c++ - 在每个类中包含 <QtGUI> 是否会导致开销?

linq - 缓慢的 LINQ 查询