【发布时间】:2015-06-13 08:23:01
【问题描述】:
我在 linux 上的一个 c++ 多线程程序中遇到了这个奇怪的错误。多线程部分基本上执行一个循环。一次迭代首先加载一个包含一些特征的 sift 文件。然后它根据树查询这些特征。由于我有很多图像,因此我使用了多个线程来进行此查询。这是代码sn-ps。
struct MultiMatchParam
{
int thread_id;
float *scores;
double *scores_d;
int *perm;
size_t db_image_num;
std::vector<std::string> *query_filenames;
int start_id;
int num_query;
int dim;
VocabTree *tree;
FILE *file;
};
// multi-thread will do normalization anyway
void MultiMatch(MultiMatchParam ¶m)
{
// Clear scores
for(size_t t = param.start_id; t < param.start_id + param.num_query; t++)
{
for (size_t i = 0; i < param.db_image_num; i++)
param.scores[i] = 0.0;
DTYPE *keys;
int num_keys;
keys = ReadKeys_sfm((*param.query_filenames)[t].c_str(), param.dim, num_keys);
int normalize = true;
double mag = param.tree->MultiScoreQueryKeys(num_keys, normalize, keys, param.scores);
delete [] keys;
}
}
我在 8 核 cpu 上运行它。起初它运行完美,所有 8 个内核的 cpu 使用率接近 100%。在每个线程查询了几张图片(大约 20 张图片)之后,性能(cpu 使用率)突然急剧下降,在所有八个内核中下降到大约 30%。
我怀疑这个错误的关键在于这行代码。
double mag = param.tree->MultiScoreQueryKeys(num_keys, normalize, keys, param.scores);
因为如果我用另一个代价高昂的操作(例如,包含 sqrt 的大型 for 循环)替换它。 cpu 使用率始终接近 100%。这个 MultiScoreQueryKeys 函数对树执行复杂的操作。由于所有八个内核都可能读取同一棵树(对这棵树没有写操作),我想知道读操作是否具有某种阻塞效应。但它不应该有这种效果,因为我在这个函数中没有写操作。循环中的操作也基本相同。如果要阻止 cpu 使用,它会在最初的几次迭代中发生。如果您需要查看此功能的详细信息或此项目的其他部分,请告诉我。
【问题讨论】:
-
您的代码包含一堆可能不相关的内容,而其他部分则丢失了。根据stackoverflow.com/help/how-to-ask提取一个最小的例子。
-
使用分析器检查那里发生了什么怎么样?
-
分析器应该有助于缩小范围。但是考虑到行为的性质,似乎在某个地方存在线程锁,代码运行时间越长,在锁中花费的时间越多,运行时间越长,争用越多,cpu 使用率越低。所以我会在某个地方寻找一个共享资源/锁,在锁内运行的时间越长,积累的工作就越多。
-
至于树是非阻塞的,如果它对读写都是线程安全的,那不一定是真的。在这种情况下,即使是直接读取也可能涉及锁定整个树(对于树来说不是一个非常有效的多线程设计,但并非那不常见)。如果是这种情况,可能值得为每个线程保留一个单独的树副本(如果这足够便宜的话)。
标签: c++ multithreading performance computer-vision