简体   繁体   English

为什么我的空间哈希值这么慢?

[英]Why Is My Spatial Hash So Slow?

Why is my spatial hash so slow? 为什么我的空间哈希这么慢? I am working on a code that uses smooth particle hydrodynamics to model the movement of landslides. 我正在编写使用平滑粒子流体动力学来模拟滑坡运动的代码。 In smooth particle hydrodynamics each particle influences the particles that are within a distance of 3 "smoothing lengths". 在平滑的粒子流体动力学中,每个粒子都会影响3个“平滑长度”范围内的粒子。 I am trying to implement a spatial hash function in order to have a fast look up of the neighboring particles. 我正在尝试实现空间哈希函数,以便快速查找相邻粒子。

For my implementation I made use of the "set" datatype from the stl. 对于我的实现,我使用了stl中的“ set”数据类型。 At each time step the particles are hashed into their bucket using the function below. 在每个时间步,使用以下函数将粒子散列到其存储区中。 "bucket" is a vector of sets, with one set for each grid cell (the spatial domain is limited). “存储桶”是集合的向量,每个网格单元具有一个集合(空间域是有限的)。 Each particle is identified by an integer. 每个粒子由整数标识。

To look for collisions the function below entitled "getSurroundingParticles" is used which takes an integer (corresponding to a particle) and returns a set that contains all the grid cells that are within 3 support lengths of the particle. 要查找碰撞,使用下面标题为“ getSurroundingParticles”的函数,该函数采用整数(对应于粒子)并返回一个集合,该集合包含在粒子的3个支持长度内的所有网格单元。

The problem is that this implementation is really slow, slower even than just checking each particle against every other particles, when the number of particles is 2000. I was hoping that someone could spot a glaring problem in my implementation that I'm not seeing. 问题在于,此实现确实很慢,甚至比仅将每个粒子与每个其他粒子进行检查(当粒子数为2000时)还要慢。我希望有人能够发现我没有看到的明显问题。

//put each particle into its bucket(s)
void hashParticles()
{
    int grid_cell0;

    cellsWithParticles.clear();

    for(int i = 0; i<N; i++)
    {
        //determine the four grid cells that surround the particle, as well as the grid cell that the particle occupies
        //using the hash function int grid_cell = ( floor(x/cell size) ) + ( floor(y/cell size) )*width
        grid_cell0 = ( floor( (Xnew[i])/cell_spacing) ) + ( floor(Ynew[i]/cell_spacing) )*cell_width;

        //keep track of cells with particles, cellsWithParticles is an unordered set so duplicates will automatically be deleted
        cellsWithParticles.insert(grid_cell0);


        //since each of the hash buckets is an unordered set any duplicates will be deleted
        buckets[grid_cell0].insert(i); 

    }
}

set<int> getSurroundingParticles(int particleOfInterest)
{
     set<int> surroundingParticles;
     int numSurrounding;
     float divisor = (support_length/cell_spacing);
     numSurrounding = ceil( divisor );
     int grid_cell;

     for(int i = -numSurrounding; i <= numSurrounding; i++)
     {
         for(int j = -numSurrounding; j <= numSurrounding; j++)
         {
             grid_cell = (int)( floor( ((Xnew[particleOfInterest])+j*cell_spacing)/cell_spacing) ) + ( floor((Ynew[particleOfInterest]+i*cell_spacing)/cell_spacing) )*cell_width;
             surroundingParticles.insert(buckets[grid_cell].begin(),buckets[grid_cell].end());
         }
     }
    return surroundingParticles;
}

The code that looks calls getSurroundingParticles: 看起来调用getSurroundingParticles的代码:

set<int> nearbyParticles;
//for each bucket with particles in it
for ( int i = 0; i < N; i++ )
 {
     nearbyParticles = getSurroundingParticles(i);
    //for each particle in the bucket

    for ( std::set<int>::iterator ipoint = nearbyParticles.begin(); ipoint != nearbyParticles.end(); ++ipoint )
    {
        //do stuff to check if the smaller subset of particles collide
    }
}

Thanks a lot! 非常感谢!

Your performance is getting eaten alive by the sheer amount of stl heap allocations caused by repeatedly creating and populating all those Sets. 重复创建和填充所有这些Set会导致大量的stl堆分配,从而使您的性能变得异常活跃。 If you profiled the code (say with a quick and easy non-instrumenting tool like Sleepy), I'm certain you'd find that to be the case. 如果您对代码进行了概要分析(例如使用像Sleepy这样的快速便捷的非仪表工具),我敢肯定您会发现情况确实如此。 You're using Sets to avoid having a given particle added to a bucket more than once - I get that. 您正在使用Set来避免将给定的粒子多次添加到存储桶中-我明白了。 If Duck's suggestion doesn't give you what you need, I think you could dramatically improve performance by using preallocated arrays or vectors, and getting uniqueness in those containers by adding an "added" flag to the particle that gets set when the item is added. 如果Duck的建议不能满足您的需求,我认为您可以通过使用预分配的数组或向量,并通过向添加该项目时设置的粒子添加“添加”标志来在这些容器中获得唯一性,从而显着提高性能。 Then just check that flag before adding, and be sure to clear the flags before the next cycle. 然后只需在添加之前检查该标志,并确保在下一个循环之前清除这些标志。 (If the number of particles is constant, you can do this extremely efficiently with a preallocated array dedicated to storing the flags, then memsetting to 0 at the end of the frame.) (如果粒子的数量是恒定的,则可以使用专用于存储标志的预分配数组,然后在帧的末尾将其设置为0来非常有效地执行此操作。)

That's the basic idea. 这是基本思想。 If you decide to go this route and get stuck somewhere, I'll help you work out the details. 如果您决定走这条路线而陷入困境,我会帮助您确定细节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM