![](/img/trans.png)
[英]How to Divide the result of a 2D String Array by the length of the subarray?
[英]How to divide Array Length into arrays with lengths that are multiples of 3
所以我有一个相当大的数组,其中包含xyz坐标,其中array [0] = x0,array [1] = y0,array [2] = z0,array [3] = x1,array [4] = y1 ...等等。
我正在此数组上运行算法,该算法花费的时间比我想要的要长,并且我想将工作分配给多个线程。 我已经设置了线程,但是我不确定如何正确划分此数组,因此我可以在3个线程中分配此工作。
即使我的数组长度可以被3整除,这也不起作用,因为将其拆分为3可以拆分xyz坐标(例如,如果我的数组大小为15,则将其除以3会得到5个数组,这意味着我正在分割XYZ坐标。
我如何拆分此数组(它的大小不必一定相等)以便可以分配工作? (例如,在前面的示例中,我希望有两个大小为6的数组和一个大小为3的数组)。
注意:数组的大小是可变的,但始终可以被3整除。
编辑:对不起,应该提到我正在使用Java。 我的算法会遍历一组坐标,并确定哪些坐标位于特定的3d形状(例如椭圆形)内。 它会保存这些坐标,并使用这些坐标执行其他任务(我正在使用计算机图形应用程序)。
EDIT2:我将详细说明算法。
基本上,我正在使用Android OpenGL-ES-3.0。 我有一个复杂的3D对象,大约有230000个顶点,接近一百万个三角形。
在应用程序中,用户将椭圆形或框(他们选择哪个)移动到靠近对象或在对象上的位置。 移动它之后,他们单击一个按钮,该按钮将运行我的算法。
该算法的目的是确定我的物体中的哪些点位于椭圆形或盒子内。 这些点随后更改为其他颜色。 但是,更复杂的是,我将变换矩阵应用于对象的点和椭球/盒子的点。
我当前的算法始于遍历对象的所有点。 对于那些在我的迭代中不清楚的人,这就是我的循环。
for(int i = 0; i < numberOfVertices*3;)
{
pointX = vertices[i];
i++;
pointY = vertices[i];
i++;
pointZ = vertices[i];
i++;
//consider transformations, then run algorithm
}
我执行必要的步骤来考虑所有转换,然后完成操作,从对象和椭圆形/盒形质心的位置得出一个点。
然后,根据形状,使用以下算法之一:
椭球体:我使用椭圆的质心并应用公式(x-c)T RT AR(x-c)(对不起,我不知道该如何格式化,我将解释该公式)。 x是一个列向量,描述了我在迭代中所处的对象的xyz点。 c是描述我质心的xyz点的列向量。 T应该意味着转置。 R是我的旋转矩阵。 A是一个对角矩阵,其条目为(1 / a ^ 2、1 / b ^ 2、1 / c ^ 2),并且我具有ab和c的值。 如果此公式> 1,则x位于我的椭球之外,并且不是有效点。 如果<= 1,则保存x。
方框:我只是检查该点是否在范围内。 如果对象的点与质心在X方向,Y方向和Z方向上相距一定距离,则将其保存。
这些算法是准确的,并且可以按预期工作。 问题显然是效率。 我似乎对什么使我的应用程序感到压力,而哪些没有导致压力,没有很好的了解。 我以为多线程可以工作,因此我尝试了所描述的一些技术,但是它们在性能上没有显着改善。 如果有人对过滤掉我的搜索有想法,所以我不必遍历所有这些观点,那将会有所帮助。
我可以建议一种稍微不同的处理方式。 我知道这不是您问题的直接答案,但请考虑一下。
如果将其实现为坐标对象(每个对象分别具有x,y和z值),则可能更容易看到。 您的“数组”现在将是1/3的长度。 您可能会认为这样做效率不高(也许是正确的),但是您会对Java可以优化事物的效果感到惊讶。 Java通常会针对人们使用最多的情况进行优化,并且您建议的手动操作该数组可能比使用对象还要慢。 在证明最易读的设计太慢之前,不应对它进行优化。
现在,您有了坐标对象的集合。 Java具有多个线程可以有效地从中拉出的队列。 将所有对象转储到队列中,并让每个线程将其拉出并通过处理并将其放入“已完成”队列中进行处理。 请注意,这使您能够轻松添加或删除线程,而不会影响代码(除了1个数字)。 您如何将基于数组的解决方案带到4个或6个线程?
祝好运
意见
假设您有17个坐标,即51个索引。 您想在3个线程中分配17个坐标。
var arraySize = 51;
var numberOfThreads = 3;
var numberOfIndexesPerCoordinate = 3;
var numberOfCoordinates = arraySize / numberOfIndexesPerCoordinate; //17 coordinates
现在在线程之间拆分那17个坐标。
var coordinatesPerThread = numberOfCoordinates / numberOfThreads; //5.6667
这不是偶数,因此您需要分配不均。 我们可以使用Math.floor和modulo进行分发。
var floored = Math.floor(coordinatesPerThread); //5 - every thread gets at least 5.
var modulod = numberOfCoordinates % floored; // 2 - there will be 2 left that need to be placed sequentially into your thread pool
这应该为您提供所需的所有信息。 在不知道您使用哪种语言的情况下,我不想提供任何实际的代码示例。
我看到您编辑了问题以将Java指定为您的语言。 我不会为您做线程工作,但是我会给出一个大概的想法。
float[] coordinates = new float[17 * 3]; //17 coordinates with 3 indexes each.
int numberOfThreads = 3;
int numberOfIndexesPerCoordinate = 3;
int numberOfCoordinates = coordinates.length / numberOfIndexesPerCoordinate ; //coordinates * 3 indexes each = 17
//Every thread has this many coordinates
int coordinatesPerThread = Math.floor(numberOfCoordinates / numberOfThreads);
//This is the number of coordinates remaining that couldn't evenly be split.
int remainingCoordinates = numberOfCoordinates % coordinatesPerThread
//To make things easier, I'm just going to track the offset in the original array. It could probably be computed instead, but its just an int.
int offset = 0;
for (int i = 0; i < numberOfThreads; i++) {
int numberOfIndexes = coordinatesPerThread * numberOfIndexesPerCoordinate;
//If this index is one of the remainders, then increase by 1 coordinate (3 indexes).
if (i < remainingCoordinates)
numberOfIndexes += numberOfIndexesPerCoordinate ;
float[] dest = new float[numberOfIndexes];
System.arraycopy(coordinates, offset, dest, 0, numberOfIndexes);
offset += numberOfIndexes;
//Put the dest array of indexes into your threads.
}
另一个可能更好的选择是使用并发双端队列,该并发双端队列具有您的所有坐标,并且每个线程都需要从中拉出,因为它们需要使用新的坐标。 对于此解决方案,您需要创建Coordinate
对象。
声明一个坐标对象
public static class Coordinate {
protected float x;
protected float y;
protected float z;
public Coordinate(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
}
声明一个任务来完成您的工作,然后将其并发双端队列传递给它。
public static class CoordinateTask implements Runnable {
private final Deque<Coordinate> deque;
public CoordinateTask(Deque<Coordinate> deque) {
this.deque = deque;
}
public void run() {
Coordinate coordinate;
while ((coordinate = this.deque.poll()) != null) {
//Do your processing here.
System.out.println(String.format("Proccessing coordinate <%f, %f, %f>.",
coordinate.x,
coordinate.y,
coordinate.z));
}
}
}
这是显示实际示例的主要方法
public static void main(String []args){
Coordinate[] coordinates = new Coordinate[17];
for (int i = 0; i < coordinates.length; i++)
coordinates[i] = new Coordinate(i, i + 1, i + 2);
final Deque<Coordinate> deque = new ConcurrentLinkedDeque<Coordinate>(Arrays.asList(coordinates));
Thread t1 = new Thread(new CoordinateTask(deque));
Thread t2 = new Thread(new CoordinateTask(deque));
Thread t3 = new Thread(new CoordinateTask(deque));
t1.start();
t2.start();
t3.start();
}
看到这个演示 。
在尝试并发优化之前,请尝试使用可使用的最有效的冲突检测方法,以尽量减少需要测试的点数,并最小化这些测试的成本。
一些一般性建议:
在进行计算之前,请考虑将所有内容归一化为公共参考系。 例如,不对每个点应用变换,而是将选择框/椭球变换为形状的坐标系,这样就可以执行碰撞检测,而无需在每次迭代中进行变换。
您也许还可以将部分或全部转换(旋转,平移等)合并到一个矩阵计算中,但是除非您执行大量转换,否则您将不会获得太多收益,您应该尝试这样做避免。
一般来说,使转换管线尽可能简化是有益的,并且将所有坐标计算保持在同一空间中,以尽可能避免转换。
尽量减少执行最慢计算所需的点数。 仅对于不能通过更快的方法排除在形状内部的点,才需要进行最精确的碰撞测试,方法是使用形状的近似值,例如球体的集合或形状的凸包。 简化形状可以使最慢的计算仅限于非常接近形状实际边界的那些点。
在过去的2D工作中,我发现即使实时计算数百个复杂动画形状的凸包,也比不使用凸包直接进行碰撞检测要快,因为它们可以更快地计算碰撞。
考虑计算/存储有关形状的其他信息,例如内部和外部碰撞球体(所有点内部为一个球体,所有点外部为一个球体),您可以将其用作快速初始过滤器。 较小球体内部的任何东西都可以保证在您的形状内,而外部球体外部的任何东西都可以在您的形状外。 您甚至可能想要存储形状的简化版本(或其凸包),可以预先计算并用于碰撞检测。
同样,在初始计算中考虑使用一个或多个球体近似椭圆体,以最大程度地减少需要测试碰撞的点。
代替计算实际距离,而是计算平方距离并将其用于比较。 但是,如果可能的话,最好使用更快的碰撞测试。 例如,对于凸多边形,可以使用“分离轴定理”,该定理将顶点投影到公共轴/平面上,从而可以非常快速地进行重叠计算。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.