将多个 std::vectors 复制到 1 的更好方法? (多线程)

Posted

技术标签:

【中文标题】将多个 std::vectors 复制到 1 的更好方法? (多线程)【英文标题】:Better way to copy several std::vectors into 1? (multithreading) 【发布时间】:2010-07-07 03:37:07 【问题描述】:

这是我正在做的事情:

我正在获取贝塞尔点并运行贝塞尔插值,然后将结果存储在 std::vector<std::vector<POINT>.

贝塞尔计算让我放慢了速度,所以这就是我所做的。

我从 std::vector<USERPOINT> 开始,它是一个结构体,带有一个点和另外 2 个用于贝塞尔句柄的点。

我将它们分成 ~4 个组,并分配每个线程来完成 1/4 的工作。为此,我创建了 4 个std::vector<std::vector<POINT> > 来存储每个线程的结果。最后,所有点都必须在 1 个连续向量中,在我使用多线程之前,我直接访问了它,但现在我保留了生成的 4 个向量的大小通过线程并将它们以正确的顺序插入到原始向量中。这行得通,但不幸的是,复制部分非常慢,并且比没有多线程的情况下要慢。所以现在我的新瓶颈是将结果复制到向量中。我怎样才能更有效地做到这一点?

谢谢

【问题讨论】:

【参考方案1】:

让所有线程像以前一样将它们的结果放入一个连续的向量中。您必须确保每个线程只访问与其他线程分开的向量部分。只要是这种情况(无论如何都应该如此-您不想两次生成相同的输出),每个人仍在使用与其他人分开的内存,并且您不需要任何锁定(等)让事情发挥作用。但是,您确实需要/想要首先确保结果的向量对于所有结果都具有正确的大小——多个线程尝试(例如)在向量上调用 resize()push_back() 匆忙造成严重破坏(更不用说导致复制,你显然想在这里避免)。

编辑:正如 Billy O'Neal 所指出的,执行此操作的通常方法是将指针传递给每个线程将存放其输出的向量的每个部分。为了争论,假设我们使用提到的std::vector<std::vector<POINT> > 作为事物的原始版本。目前,我将跳过创建线程的细节(尤其是因为它因系统而异)。为简单起见,我还假设要生成的曲线数是线程数的精确倍数——实际上,曲线不会完全均匀地划分,所以你必须“捏造”算一个线程,但这与手头的问题无关。

std::vector<USERPOINT> inputs; // input data   
std::vector<std::vector<POINT> > outputs; // space for output data

const int thread_count = 4;

struct work_packet            // describe the work for one thread
    USERPOINT *inputs;         // where to get its input
    std::vector<POINT> *outputs;   // where to put its output
    int num_points;                // how many points to process
    HANDLE finished;               // signal when it's done.
;

std::vector<work_packet> packets(thread_count); // storage for the packets.
std::vector<HANDLE> events(thread_count);       // storage for parent's handle to events

outputs.resize(inputs.size);                    // can't resize output after processing starts.

for (int i=0; i<thread_count; i++) 
    int offset = i * inputs.size() / thread_count;
    packets[i].inputs = &inputs[0]+offset;
    packets[i].outputs = &outputs[0]+offset;
    packets[i].count = inputs.size()/thread_count;
    events[i] = packets[i].done = CreateEvent();

    threads[i].process(&packets[i]);



// wait for curves to be generated (Win32 style, for the moment).
WaitForMultipleObjects(&events[0], thread_count, WAIT_ALL, INFINITE);

请注意,尽管我们必须确保 outputs 向量在被多个线程操作时不会调整大小,但 in 输出点的单个向量 可以 em> 是,因为每个线程一次只能被一个线程触及。

【讨论】:

+1 但请注意:您可能必须使用指向向量中元素的指针,而不是在此处传递向量本身,因为 STL 容器在多线程行为方面可能很奇怪。 我认为@Billy ONeal 的关注非常重要,以至于在我给您指出之前,您需要将其作为答案的一部分。一些示例代码也会有所帮助。【参考方案2】:

如果事物之间的简单复制比您开始使用多线程之前慢,那么您所做的简单操作很可能不会扩展到多核。如果是像贝塞尔曲线这样简单的东西,我怀疑会是这样。

请记住,创建线程等的开销会影响总运行时间。

最后..对于副本,您使用的是什么?是std::copy吗?

【讨论】:

【参考方案3】:

多线程不会加快你的进程。可以在不同的内核中处理数据。

【讨论】:

我认为 OP 并不愚蠢。显然使用多线程的重点是使用多核。

以上是关于将多个 std::vectors 复制到 1 的更好方法? (多线程)的主要内容,如果未能解决你的问题,请参考以下文章

包装 std::vector 的 std::vectors,C++ SWIG Python

两个 std::vectors 之间的匹配元素

插入向量变换

带有 std::vectors 的图形?

具有预定义大小的 C++ std::vectors

如何将一个 std::queue 的内容附加到另一个