我们有一个给定的3D网格,我们试图消除相同的顶点。为此,我们使用一个自定义的结构,包含顶点坐标和相应的法线。
struct vertice
{
float p1,p2,p3,n1,n2,n3;
bool operator == (const vertice& vert) const
{
return (p1 == vert.p1 && p2 == vert.p2 && p3 == vert.p3);
}
};
用数据填充顶点后,会将其添加到unordered_set中以删除重复项。
struct hashVertice
{
size_t operator () (const vertice& vert) const
{
return(7*vert.p1 + 13*vert.p2 + 11*vert.p3);
}
};
std::unordered_set<vertice,hashVertice> verticesSet;
vertice vert;
while(i<(scene->mMeshes[0]->mNumVertices)){
vert.p1 = (float)scene->mMeshes[0]->mVertices[i].x;
vert.p2 = (float)scene->mMeshes[0]->mVertices[i].y;
vert.p3 = (float)scene->mMeshes[0]->mVertices[i].z;
vert.n1 = (float)scene->mMeshes[0]->mNormals[i].x;
vert.n2 = (float)scene->mMeshes[0]->mNormals[i].y;
vert.n3 = (float)scene->mMeshes[0]->mNormals[i].z;
verticesSet.insert(vert);
i = i+1;
}
我们发现它对于像3.000.000顶点这样的数据量来说太慢了。即使运行15分钟后程序也没有完成。是否存在我们未看到的瓶颈,或者是否有更好的数据结构用于此类任务?
答案 0 :(得分:6)
如果您只是从循环中移除verticesSet.insert(vert);
会怎样?
如果它显着加速(正如我预期的那样),你的瓶颈就在std::unordered_set
的内部,这是一个哈希表,哈希表的主要潜在性能问题是在那里是过多的哈希冲突。
在您当前的实施中,如果p1
,p2
和p3
小,则不同哈希码的数量会很小(因为您“崩溃” “浮动到整数”并且会有很多碰撞。
如果上述假设结果为真,我会尝试以不同的方式实现散列函数(例如,乘以更大的系数)。
除此之外,如其他人已经建议的那样,对您的代码进行概要分析。
答案 1 :(得分:1)
散列浮点可能很棘手。特别是你的哈希
例程将哈希计算为浮点值
将其转换为无符号整数类型。这很严重
如果顶点可以很小的问题:如果所有的顶点
在[0...1.0)
范围内,例如,您的哈希函数
永远不会返回任何大于13的东西。作为一个未签名的
整数,表示最多有13个不同
哈希码。
散列浮点的常用方法是对二进制进行散列
图像,首先检查特殊情况。 (0.0
和-0.0
有不同的二进制图像,但必须散列相同。它就是
一个开放的问题你用NaN
s做了什么。)对于float
这是
特别简单,因为它通常具有相同的尺寸
int
,您可以reinterpret_cast
:
size_t
hash( float f )
{
assert( /* not a NaN */ );
return f == 0.0 ? 0.0 : reinterpret_cast( unsigned& )( f );
}
我知道,正式来说,这是未定义的行为。但如果漂浮和 int具有相同的大小,unsigned没有陷印 表示(大多数通用机器上的情况) 今天),然后是一个错误的编译器 故意迟钝。
然后使用任何组合算法合并三个结果; 你使用的那个和其他任何一个一样好(在这种情况下 - 它是 不是一个好的通用算法。)
我可能会补充说,虽然有些评论坚持要进行分析
(这通常是一个很好的建议),如果你需要15分钟
对于300万个值,问题实际上只是一个糟糕的哈希
功能,导致大量的碰撞。没有别的
导致表现不佳。除非你熟悉
通常的std::unordered_set
的内部实现
profiler输出可能不会给你提供太多信息。
另一方面,std::unordered_set
确实具有功能
例如bucket_count
和bucket_size
,允许分析
哈希函数的质量。在你的情况下,如果你不能
创建一个包含300万个条目的unordered_set
,这是您的第一个条目
步骤应该是创建一个小得多的,并使用这些
用于评估哈希码的质量。
答案 2 :(得分:0)
如果存在瓶颈,你肯定没有看到它,因为你没有包括任何时间措施。
使用分析器或仅手动测量算法的时间。这将让你找到瓶颈 - 如果有的话。
这是正确的进行方式。根据我的经验,期待自己,或者StackOverflow用户通过眼睛检查发现瓶颈,而不是实际测量程序中的时间,这是优化尝试失败的最常见原因。