写入数组时,最后一个线程的执行速度比第一个线程慢
Last threads execute slower than first threads while writing to an array
我正在尝试优化Mandelbrot集生成器,问题是我试图通过使用_beginthread()函数使其成为多线程的。我正在解决的计算问题是在2D平面上运行一个函数,我试图同时运行大约8个线程,每个线程计算2D阵列的一部分(行),但我注意到,完成的第一个线程比完成的最后一个线程快得多。这是输出:
Starting thread 0
Starting thread 1
Starting thread 2
Starting thread 3
Starting thread 4
Starting thread 5
Starting thread 6
Starting thread 7
Ending thread 0 - Time taken: 1062ms
Ending thread 7 - Time taken: 1031ms
Ending thread 1 - Time taken: 1610ms
Ending thread 6 - Time taken: 1563ms
Ending thread 2 - Time taken: 10265ms
Ending thread 5 - Time taken: 10219ms
Ending thread 4 - Time taken: 31609ms
Ending thread 3 - Time taken: 31641ms
每个线程都有相同的事情要做,但数字不同,我不明白为什么我会得到这些时间这就是我多线程的方式:
#define HEIGHT 4000
#define WIDTH 4000
#define MAX_THREADS 8
int const maxIterations = 150;
int bitmap[HEIGHT][WIDTH];
bool finishedThreads[MAX_THREADS];
void renderRow(void * arg) {
int startTime = GetTickCount();
int * threadNumPinter = (int*)arg;
int threadNum = *threadNumPinter;
int startRow = threadNum * (HEIGHT / MAX_THREADS);
for (int y = startRow; y <= startRow+(HEIGHT / MAX_THREADS); y++) {
for (int x = 0; x <= WIDTH; x++) {
double xx = (((double)x / (double)WIDTH) * 4.0) - 2.0;
double yy = (((double)y / (double)HEIGHT) * 4.0) - 2.0;
bitmap[x][y] = isPartOfSet(xx, yy) * 10;
}
}
threadNum = startRow / (HEIGHT / MAX_THREADS);
finishedThreads[threadNum] = true;
cout << "Ending thread " << threadNum << " - Time: " << GetTickCount() - startTime << "ms" << endl;
_endthread();
}
int main() {
int startTime = GetTickCount();
HANDLE hThread;
HANDLE ghEvents[2];
DWORD dwThreadID;
int rowsPerThread = HEIGHT / MAX_THREADS;
int arg;
int threadIds[MAX_THREADS];
for (int i = 0; i < MAX_THREADS; i ++) {
threadIds[i] = i;
cout << "Starting thread " << i << endl;
arg = i;
_beginthread(renderRow, 0, &threadIds[i]);
Sleep(10);
}
bool done = true;//Wait for all threads to finish
while (1) {
for (int i = 0; i < MAX_THREADS; i++){
if (finishedThreads[i] == false)done = false;
}
if (done == true) break;
else done = true;
Sleep(20);
}
saveBitmap(WIDTH, HEIGHT);
cout << endl << "Rendered in " << double(GetTickCount() - startTime) / 1000.0 << " seconds" << endl;
cin.get();
main();
}
显然还有更多的代码,但我不认为它对这个问题有任何影响。我在这里做错了什么?我在CUDA上也遇到过同样的问题,所以我相信这就是我实现多线程的方式。谢谢
在我的回答中,我既不涉及线程/同步问题,也不涉及缓存问题——请参阅其他回答/评论。
我的观点不同:你写"每个线程都有相同的事情要做,但数字不同"。如果我在mandelbrot集合上的记忆对我来说是正确的,那么确定一个点是否是集合的成员(IOW是您的isPartOfSet
函数的实现,您没有提供)是一个迭代过程。有些点很快"退出",有些点没有,你必须继续迭代,直到你预定义的最大迭代次数。
所以我想说的是:通过"每个线程一个大块"的并行化,线程占用的时间可能会明显不同,这是很自然的。
这类问题的解决方案是将问题(即图像)分成更小的部分,其大小而不是取决于线程的数量,但应根据经验选择a)不太大以防止工作分配不均(如您的巨大块示例),b)不太小以导致过多的组织开销。
因此,现在,您有M个线程和N个工作块(使用N>>M),并且您需要一个实现,让每个线程在类似的循环中工作
while (worktodo) fetch_a_chunk_of_work_and_do_it ()
这种生产者/消费者模式是如何实现的——我将把它留给其他人来描述(或者让你谷歌:-)
全局变量的错误并发使用的经典示例。
bool finishedThreads[MAX_THREADS];
是全局的,并且可以从多个线程访问(写入/读取)。你不能指望这会奏效。对于您的情况,您甚至不应该使用这个变量。相反,您应该等待线程完成的事件。
8个线程的硬编码很糟糕,那么一些用户的双核笔记本电脑呢?CCD_ 2。
睡眠很糟糕。你的旋转循环绝对不是正确的方式。对不起,只是说实话。
使用std::thread
和join
等待它们完成。更好的做法是:在其他线程上执行除一个工作项外的所有工作项,在主线程上执行一个,然后连接其他线程。如果有N个CPU,那么您应该创建N-1个线程,并在主线程上执行一项操作。
既然有更好的标准C++库类,为什么要使用仅限Windows的API?
建议避免Sleep
如果仅仅等待线程退出是不够的(使用上面提到的联接),那么在更复杂的场景中,应该使用std::mutex
、std::unique_lock
和std::condition_variable
。
当通知发生时,您应该有一个设置为true的变量。在等待的代码中,获取互斥对象,检查该标志,如果未设置,则对条件变量调用wait
。
在通知另一个线程的线程中,获取互斥,设置我提到的标志变量,对条件变量使用notify_one
或notify_all
方法。
请在cppreference上查看此引用。不过,你使用的主要是我已经提到的那些。
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 线程相互减慢速度
- 多线程减慢程序速度:无错误共享,无互斥锁,无缓存未命中,无小工作量
- 当 2 个线程共享同一物理内核时,具有错误共享的易失性增量在发布中的运行速度比在调试中慢
- 有人可以解释为什么使用 OpenMP 部分的运行速度比单个线程慢吗?
- 在不减慢线程速度的情况下保存大量数据
- C++ OpenMP 斐波那契:1 个线程的执行速度比 4 个线程快得多
- 通过创建单个线程来运行一段代码可加快执行速度
- 线程锁定互斥锁的速度比 std::conditional_variable::wait() 快
- C++ 并发队列:速度较慢,> 1 个线程
- 随着线程数量的增加,OpenMP的实现速度越来越慢
- 如何在不冻结线程/应用程序的情况下减慢方法执行速度
- 具有`k`线程的多线程程序的运行速度都比其顺序版本快
- 为什么std::async与简单的分离线程相比速度较慢
- 多线程不会改变速度
- 线程似乎正在减慢图像处理C++11的速度
- 线程加载图像的速度更快,直到它们在Studio中消失
- C++线程化的应用程序比非线程化的运行速度慢
- 一般 openMP - 线程速度不同
- c++线程速度测试,我做得对吗?