Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ c++;:螺纹管路平衡_C++_Multithreading_Pipeline - Fatal编程技术网

C++ c++;:螺纹管路平衡

C++ c++;:螺纹管路平衡,c++,multithreading,pipeline,C++,Multithreading,Pipeline,我有一个块数组,首先需要处理,然后再组合块可以以任意顺序处理,但需要按照它们在数组中出现的顺序进行组合 以下伪代码显示了我的第一种方法: array chunks; def worker_process(chunks): while not all_chunks_processed: // get the next chunk that isn't processed or in processing yet get_next_chunk()

我有一个
块数组
,首先需要
处理
,然后再
组合
<代码>块可以任意顺序处理,但需要按照它们在数组中出现的顺序进行组合

以下伪代码显示了我的第一种方法:

array chunks;

def worker_process(chunks):
    while not all_chunks_processed:
        // get the next chunk that isn't processed or in processing yet
        get_next_chunk()
        process_chunk()

def worker_combine(chunks):
    for i=0 to num_chunks:
        // wait until chunk i is processed
        wait_until(chunks[i].is_processed())
        combine_chunk(i)

def main():
    array chunks;

    // execute worker_process in n threads where n is the number of (logical) cores
    start_n_threads(worker_process, chunks)

    // wait until all processing threads are finished
    join_threads()

    // combine chunks in a single thread
    start_1_thread(worker_combine, chunks)

    // wait until combine thread is finished
    join_threads()
对上述算法的测量表明,并行处理所有数据块和按顺序组合处理的数据块都需要大约3秒的时间,这导致总运行时间大约为6秒

我使用的是24核CPU,这意味着在联合收割机阶段,只使用其中一个核。我当时的想法是使用管道来减少执行时间。我的期望是,使用管道的执行时间应该在3到4秒之间。这是使用管道时主功能的变化方式:

def main():
    array chunks;

    // execute worker_process in n threads where n is the number of (logical) cores
    start_n_threads(worker_process, chunks)

    // combine chunks in a single thread
    start_1_thread(worker_combine, chunks)

    // wait until ALL threads are finished
    join_threads()
这一变化略微降低了运行时间,但远没有我预期的那么多。我发现所有处理线程都在3到4秒后完成,而combine线程还需要大约2秒

问题是调度程序平等地处理所有线程,这导致联合线程暂停

现在的问题是:

如何更改管道,使combine线程在仍然利用所有内核的情况下执行得更快

我已经尝试过减少处理线程的数量,这有点帮助,但这会导致一些内核根本没有被使用,这也不好

编辑:


虽然这个问题在这里不是语言特定的,但实际上我需要在C++ 14中实现。

< P>你可以使你的工作者线程不那么专业化。因此,每当一个工作线程空闲时,它都可以寻找要做的工作;如果一个区块已处理但未合并,且当前没有线程正在合并,则该线程可以为该区块运行合并。否则,它可以检查未处理的队列以查找下一个要处理的块

更新

首先,我想了一下为什么这可能(或可能不会)有帮助;第二,从评论中可以明显看出,还需要一些额外的澄清

但在我开始之前,你是否真的尝试过这种方法,看看它是否有帮助?因为事实是,关于并行处理的推理很困难,这就是为什么并行处理框架尽其所能简化假设的原因。因此,如果你想知道这是否有帮助,试着去做,让结果引导对话。事实上,我们都不能肯定这是否会有帮助

所以,这种方法给你的是一种更为流畅的对核心工作的接受。而不是有一个工人,如果轮到他时有工作,他会做那项工作,但不会做其他任何事情,而X(比如24)个工人即使准备好了也永远不会做那项任务,你有一批工人在做需要做的事情

现在,这是一个简单的现实,在任何时候,当一个核心被用来组合,一个更少的核心将可用于处理比否则。每种工作所花费的处理器总时间是恒定的。所以这些都不是要优化的变量。我们想要的是在任何时候分配资源,以接近总工作量的比例

现在要进行详细分析,我们需要知道每个任务(处理任务、组合任务)是否受处理器限制(以及一百万个后续问题,取决于答案)。我不知道这一点,所以以下只是大致准确

您的初始数据表明,您在合并上花费了3秒的单个处理时间;我们就称之为3个工作单元吧

您在24个内核上花费了3秒的并行处理时间来完成处理任务。让我们把它写成72个工作单元

因此,我们猜测,将大约1/25的资源用于组合并不坏,但序列化约束可能会阻止您实现这一比例。(再说一次,如果处理器以外的其他资源是一个或两个任务中的真正瓶颈,那么这个比例无论如何都可能是完全错误的。)

如果您能够确保100%的利用率而不让组合器线程睡着,那么您的管道方法应该接近这一点。但它可能会睡着,要么是因为工作还没有准备好,要么是因为它有时会失去工作。你不能对前者做太多,也许问题是你能解决后者吗

可能有一些特定于体系结构的游戏,您可以使用线程优先级或关联性来玩,但您指定了可移植性,如果您玩这些游戏,我最多只能期望您必须重新调整每个特定硬件的参数。再说一次,我的问题是,我们能不能用更简单的方法

我的建议背后的直觉很简单:运行足够的工作人员让系统保持忙碌,让他们做任何准备好做的工作

这种方法的局限性在于,如果工作人员在进行联合收割机作业时处于睡眠状态,则联合收割机管道将暂停。但是,除非你能预防“正在进行联合工作的线程”——无论是专门的线程还是正在进行联合工作单元的工作线程——被放在一边让其他线程运行,否则你就无能为力了。再说一遍,我不是说没有办法——但我是说没有可移植的方法,特别是在没有特定于机器的调优的情况下,这种方法可以最佳地运行

即使您在一个可以直接将一个内核分配给组合器线程的系统上,这也可能不是最优的,因为(a)组合工作仍然只能在处理任务完成时完成,并且(b)任何时候组合工作还没有准备好,保留的内核都将处于空闲状态

不管怎么说,我猜在这种情况下,一个普通工人会被解雇
join_arr;
#pragma omp parallel
{
  double local_result;
#pragma omp for
  for (i=0; i<N; i++) {
    do work()
#pragma omp critical
    join()
  } // end of for loop
}
int main()
{
   arr some_arr;
   using foreach  = raft::for_each< type_t >;
   foreach fe( some_arr, arr_size, thread_count );
   raft::map m;
   /**
    * send data, zero copy, from fe to join as soon as items are
    * ready to be joined, so everything is done fully in parallel
    * where fe is duplicated on fibers/threads up to thread_count
    * wide and the join is on a separate fiber/thread and gathering
    */
   m += fe >> join;
   m.exe();
}