我注意到为一个代码运行一个线程要比拥有一个线程慢得多,而且我一直在努力地想知道为什么,有人可以帮忙吗?
代码说明: 我有时有一个非常大的数组,我需要以并行的方式处理部分数组以进行优化,每一行的“一部分”都会在特定线程中循环并进行处理,现在我注意到,如果我只是有一个“部分”,即整个数组和贯穿其中的单个工作线程比将数组划分并作为具有不同线程的单独子数组处理时要快得多。
bool m_generate_row_worker(ull t_row_start,ull t_row_end)
{
for(;t_row_start<t_row_end;t_row_start++)
{
m_current_row[t_row_start]=m_singularity_checker(m_previous_row[t_row_start],m_shared_random_row[t_row_start]);
}
return true;
}
...
//code
...
for(unsigned short thread_indx=0;thread_indx<noThreads-1;thread_indx++)
{
m_threads_array[thread_indx]=std::thread(
m_generate_row_worker,this,
thread_indx*(m_parts_per_thread),(thread_indx+1)*(m_parts_per_thread));
}
m_threads_array[noThreads-1]=std::thread(m_generate_row_worker,this,
(noThreads-1)*(m_parts_per_thread),std::max((noThreads)*(m_parts_per_thread),m_blocks_per_row));
//join
for(unsigned short thread_indx=0;thread_indx<noThreads;thread_indx++)
{
m_threads_array[thread_indx].join();
}
//EDIT
inline ull m_singularity_checker(ull t_to_be_ckecked_with,ull
t_to_be_ckecked)
{
return (t_to_be_ckecked & (t_to_be_ckecked_with<<1)
& (t_to_be_ckecked_with>>1) ) | (t_to_be_ckecked_with &
t_to_be_ckecked);
}
答案 0 :(得分:3)
为什么在某些特定情况下具有多个线程(并行处理)会降低性能?
结论:线程并不是自动提高程序性能的灵丹妙药。
关于您的程序,鉴于您所摘录的内容,我们无法排除上述任何潜在问题。
避免或发现上述问题的一些提示:
答案 1 :(得分:1)
使用线程并不总是意味着您将完成更多的工作。例如,使用2个线程并不意味着您将在一半时间内完成任务。设置线程有开销,具体取决于线程和操作系统的数量等。线程之间发生了多少上下文切换(保存线程堆栈/ reg并加载下一个线程/ regs-所有这些加起来)。在某个时候添加更多线程将开始减慢您的程序速度,因为将花费更多的时间在线程之间切换/设置线程启动/关闭,然后才能完成工作。所以你可能是这个的受害者。
如果您有100个非常小的项目(如1条指令)要做,那么由于您现在有("many instructions" + 1) x 100
的工作要做,因此可以保证100个线程的速度变慢。 “许多指令”是设置线程并最终清除它们并在它们之间切换的工作。
因此,您可能想开始自己分析它。.处理每一行要完成多少工作,总共要设置多少个线程?
一种非常粗略但快速/简单的测量方法是仅花费时间单独处理一行(例如,使用std::chrono
函数在处理一行开始时测量时间,然后然后花点时间查看总时间,然后也许对整个表进行相同的测试,以了解总时间。
如果您发现单个行花费的时间很少,那么您可能不会从线程中获得太多好处...您最好将表拆分成等于核心数量的工作块您的CPU拥有,然后开始更改线程数(+/-)来找到最佳位置。仅基于行数创建线程是一个糟糕的选择-您真的想设计它以最大化每个核心(例如)。
因此,如果您有4个内核,则可能首先将工作分成4个线程开始。然后用8进行测试,如果尝试16更好,如果尝试12不好,等等...
另外,您在不同的PC上可能会得到不同的结果...