第09章 - 性能优化与加速
第09章 - 性能优化与加速
9.1 性能优化概述
9.1.1 性能考量因素
geometry-api-java 的性能受以下因素影响:
- 几何复杂度:顶点数量、环数量
- 操作类型:拓扑操作比关系判断更耗时
- 数据规模:处理的几何对象数量
- 内存使用:大几何对象的内存占用
- 算法效率:不同实现方式的效率差异
9.1.2 优化策略概览
性能优化策略
├── 几何加速(Geometry Acceleration)
│ └── 光栅化和四叉树预处理
├── 空间索引
│ ├── QuadTree
│ └── Envelope2DIntersector
├── 批量处理
│ └── GeometryCursor
├── 内存优化
│ ├── 对象复用
│ └── 流式处理
└── 算法选择
└── 根据场景选择合适的操作
9.2 几何加速
9.2.1 加速原理
geometry-api-java 通过预处理几何对象来加速重复的空间操作:
// 加速结构
GeometryAccelerators
├── RasterizedGeometry2D // 光栅化表示
└── QuadTree // 四叉树索引
加速适用场景:
- 一个几何与大量其他几何进行关系判断
- 重复查询同一个几何
9.2.2 使用几何加速
Polygon largePolygon = createLargeComplexPolygon();
SpatialReference sr = SpatialReference.create(4326);
// 获取支持加速的算子
OperatorContains containsOp = OperatorContains.local();
// 检查是否可以加速
boolean canAccelerate = containsOp.canAccelerateGeometry(largePolygon);
System.out.println("可加速: " + canAccelerate);
if (canAccelerate) {
// 执行加速预处理
containsOp.accelerateGeometry(
largePolygon,
sr,
Geometry.GeometryAccelerationDegree.enumMedium
);
}
// 批量查询(现在会更快)
List<Point> points = getMillionsOfPoints();
int containedCount = 0;
for (Point point : points) {
if (containsOp.execute(largePolygon, point, sr, null)) {
containedCount++;
}
}
System.out.println("包含点数: " + containedCount);
// 完成后释放加速资源
Operator.deaccelerateGeometry(largePolygon);
9.2.3 加速级别
public enum GeometryAccelerationDegree {
enumMild, // 轻度:64×64×2 位光栅
enumMedium, // 中度:256×256×2 位光栅 + 线段四叉树
enumHot // 高度:1024×1024×2 位光栅 + 线段四叉树
}
选择建议:
enumMild:内存有限或几何简单时enumMedium:大多数场景的推荐选择enumHot:大量查询且内存充足时
9.2.4 加速的开销
// 加速有预处理开销
// 只有在查询次数足够多时才值得
// 规则:
// - 少于 10 次查询:不值得加速
// - 10-100 次查询:enumMild
// - 100-1000 次查询:enumMedium
// - 超过 1000 次查询:enumHot
int expectedQueries = estimateQueryCount();
Geometry.GeometryAccelerationDegree degree;
if (expectedQueries < 10) {
degree = null; // 不加速
} else if (expectedQueries < 100) {
degree = Geometry.GeometryAccelerationDegree.enumMild;
} else if (expectedQueries < 1000) {
degree = Geometry.GeometryAccelerationDegree.enumMedium;
} else {
degree = Geometry.GeometryAccelerationDegree.enumHot;
}
9.3 空间索引
9.3.1 QuadTree
// 创建四叉树
Envelope2D extent = new Envelope2D();
extent.setCoords(0, 0, 1000, 1000);
int height = 8; // 树高度,影响精度
QuadTree quadTree = new QuadTree(extent, height);
// 向四叉树添加元素
List<Geometry> geometries = getGeometries();
for (int i = 0; i < geometries.size(); i++) {
Envelope2D env = new Envelope2D();
geometries.get(i).queryEnvelope2D(env);
// 插入元素,返回元素句柄
int elementHandle = quadTree.insert(i, env);
}
// 查询与包围盒相交的元素
Envelope2D queryEnv = new Envelope2D();
queryEnv.setCoords(100, 100, 200, 200);
QuadTree.QuadTreeIterator iterator = quadTree.getIterator(queryEnv, 0.0);
int elementHandle;
while ((elementHandle = iterator.next()) != -1) {
int elementIndex = quadTree.getElement(elementHandle);
Geometry candidate = geometries.get(elementIndex);
// 进行精确检查...
}
9.3.2 Envelope2DIntersector
用于批量包围盒相交检测:
// 创建相交器
Envelope2DIntersector intersector = new Envelope2DIntersector();
// 添加几何的包围盒
List<Geometry> geometries = getGeometries();
for (int i = 0; i < geometries.size(); i++) {
Envelope2D env = new Envelope2D();
geometries.get(i).queryEnvelope2D(env);
intersector.addEnvelope(i, env);
}
// 启动相交检测
intersector.startIntersecting();
// 获取相交对
while (intersector.next()) {
int handle1 = intersector.getHandle_1();
int handle2 = intersector.getHandle_2();
// 这两个几何的包围盒相交
Geometry g1 = geometries.get(handle1);
Geometry g2 = geometries.get(handle2);
// 进行精确的空间关系检查
}
9.3.3 IntervalTree
用于一维区间的快速查询:
// 创建区间树
IntervalTreeImpl intervalTree = new IntervalTreeImpl();
// 添加区间
intervalTree.addInterval(0, 10); // 区间 [0, 10]
intervalTree.addInterval(5, 15); // 区间 [5, 15]
intervalTree.addInterval(12, 20); // 区间 [12, 20]
// 查询与给定区间相交的区间
IntervalTreeImpl.IntervalTreeIteratorImpl iterator =
intervalTree.getIterator(8, 14);
int handle;
while ((handle = iterator.next()) != -1) {
double min = intervalTree.getIntervalMin(handle);
double max = intervalTree.getIntervalMax(handle);
System.out.println("相交区间: [" + min + ", " + max + "]");
}
9.4 批量处理优化
9.4.1 使用 GeometryCursor
// 低效方式:逐个处理
List<Geometry> results = new ArrayList<>();
for (Geometry geom : geometries) {
Geometry buffered = GeometryEngine.buffer(geom, sr, 10.0);
results.add(buffered);
}
// 高效方式:使用 Cursor
SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geometries);
GeometryCursor resultCursor = OperatorBuffer.local().execute(
inputCursor, sr, new double[]{10.0}, false, null);
List<Geometry> results2 = new ArrayList<>();
Geometry result;
while ((result = resultCursor.next()) != null) {
results2.add(result);
}
9.4.2 自定义 GeometryCursor
/**
* 从数据库流式读取几何的 Cursor
*/
public class DatabaseGeometryCursor extends GeometryCursor {
private ResultSet resultSet;
private int currentId = -1;
public DatabaseGeometryCursor(ResultSet rs) {
this.resultSet = rs;
}
@Override
public Geometry next() {
try {
if (!resultSet.next()) {
return null;
}
currentId = resultSet.getInt("id");
byte[] wkb = resultSet.getBytes("geom");
return OperatorImportFromWkb.local().execute(
0, Geometry.Type.Unknown, ByteBuffer.wrap(wkb), null);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public int getGeometryID() {
return currentId;
}
}
9.4.3 并行处理
/**
* 并行缓冲区计算
*/
public List<Geometry> parallelBuffer(List<Geometry> geometries,
SpatialReference sr, double distance) {
return geometries.parallelStream()
.map(geom -> GeometryEngine.buffer(geom, sr, distance))
.collect(Collectors.toList());
}
/**
* 使用 ForkJoinPool 进行并行空间查询
*/
public List<Geometry> parallelSpatialQuery(Geometry query,
List<Geometry> candidates, SpatialReference sr) {
return candidates.parallelStream()
.filter(geom -> !GeometryEngine.disjoint(query, geom, sr))
.collect(Collectors.toList());
}
9.5 内存优化
9.5.1 对象复用
// 复用 Envelope2D
Envelope2D env = new Envelope2D();
for (Geometry geom : geometries) {
geom.queryEnvelope2D(env); // 复用 env
// 使用 env...
}
// 复用 Point2D
Point2D pt = new Point2D();
Polyline line = getPolyline();
for (int i = 0; i < line.getPointCount(); i++) {
line.getXY(i, pt); // 复用 pt
// 使用 pt...
}
9.5.2 内存估算
// 估算几何内存占用
long estimatedSize = geometry.estimateMemorySize();
System.out.println("估计内存: " + estimatedSize + " 字节");
// 批量估算
long totalSize = 0;
for (Geometry geom : geometries) {
totalSize += geom.estimateMemorySize();
}
System.out.println("总内存: " + (totalSize / 1024 / 1024) + " MB");
9.5.3 流式处理大文件
/**
* 流式处理大型 GeoJSON 文件
*/
public void processLargeGeoJsonFile(String filePath,
Consumer<Geometry> processor) throws IOException {
try (BufferedReader reader = new BufferedReader(
new FileReader(filePath))) {
// 假设是 FeatureCollection,逐个处理 Feature
// 实际实现需要更复杂的 JSON 流式解析
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("\"geometry\"")) {
// 提取并解析几何
String geomJson = extractGeometry(line);
Geometry geom = parseGeoJson(geomJson);
processor.accept(geom);
}
}
}
}
9.6 算法优化
9.6.1 预过滤
/**
* 使用包围盒预过滤优化空间查询
*/
public List<Geometry> optimizedSpatialQuery(Geometry query,
List<Geometry> candidates, SpatialReference sr) {
// 获取查询几何的包围盒
Envelope2D queryEnv = new Envelope2D();
query.queryEnvelope2D(queryEnv);
List<Geometry> results = new ArrayList<>();
Envelope2D candidateEnv = new Envelope2D();
for (Geometry candidate : candidates) {
// 快速包围盒检查
candidate.queryEnvelope2D(candidateEnv);
if (!queryEnv.isIntersecting(candidateEnv)) {
continue; // 快速排除
}
// 精确检查
if (!GeometryEngine.disjoint(query, candidate, sr)) {
results.add(candidate);
}
}
return results;
}
9.6.2 简化大几何
/**
* 对大几何进行预简化以提高性能
*/
public Geometry optimizeForQuery(Geometry geometry, double tolerance) {
if (geometry instanceof MultiVertexGeometry) {
MultiVertexGeometry mvg = (MultiVertexGeometry) geometry;
if (mvg.getPointCount() > 1000) {
// 简化以减少顶点
return OperatorGeneralize.local().execute(
geometry, tolerance, true, null);
}
}
return geometry;
}
9.6.3 分块处理
/**
* 将大范围查询分块处理
*/
public List<Geometry> chunkedSpatialQuery(Geometry query,
List<Geometry> candidates, SpatialReference sr, int chunkSize) {
List<Geometry> results = new ArrayList<>();
// 分块处理
for (int i = 0; i < candidates.size(); i += chunkSize) {
int end = Math.min(i + chunkSize, candidates.size());
List<Geometry> chunk = candidates.subList(i, end);
// 处理块
for (Geometry candidate : chunk) {
if (!GeometryEngine.disjoint(query, candidate, sr)) {
results.add(candidate);
}
}
// 可选:显式触发 GC
if (i % (chunkSize * 10) == 0) {
System.gc();
}
}
return results;
}
9.7 性能监控
9.7.1 操作计时
public class GeometryTimer {
public static <T> T timed(String operation, Supplier<T> task) {
long start = System.nanoTime();
T result = task.get();
long duration = System.nanoTime() - start;
System.out.printf("%s: %.2f ms%n", operation, duration / 1_000_000.0);
return result;
}
public static void timed(String operation, Runnable task) {
long start = System.nanoTime();
task.run();
long duration = System.nanoTime() - start;
System.out.printf("%s: %.2f ms%n", operation, duration / 1_000_000.0);
}
}
// 使用
Geometry result = GeometryTimer.timed("Buffer",
() -> GeometryEngine.buffer(polygon, sr, 10.0));
9.7.2 内存监控
public class MemoryMonitor {
public static void printMemoryUsage(String label) {
Runtime runtime = Runtime.getRuntime();
long used = runtime.totalMemory() - runtime.freeMemory();
long max = runtime.maxMemory();
System.out.printf("%s - 已用: %.1f MB, 最大: %.1f MB%n",
label, used / 1024.0 / 1024.0, max / 1024.0 / 1024.0);
}
public static void forceGC() {
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
9.8 性能基准测试
9.8.1 基准测试框架
public class GeometryBenchmark {
private static final int WARMUP_ITERATIONS = 5;
private static final int MEASURE_ITERATIONS = 20;
public static BenchmarkResult benchmark(String name, Runnable task) {
// 预热
for (int i = 0; i < WARMUP_ITERATIONS; i++) {
task.run();
}
// 测量
long[] times = new long[MEASURE_ITERATIONS];
for (int i = 0; i < MEASURE_ITERATIONS; i++) {
long start = System.nanoTime();
task.run();
times[i] = System.nanoTime() - start;
}
return new BenchmarkResult(name, times);
}
public static class BenchmarkResult {
public final String name;
public final double avgMs;
public final double minMs;
public final double maxMs;
public BenchmarkResult(String name, long[] timesNs) {
this.name = name;
this.avgMs = Arrays.stream(timesNs).average().orElse(0) / 1_000_000.0;
this.minMs = Arrays.stream(timesNs).min().orElse(0) / 1_000_000.0;
this.maxMs = Arrays.stream(timesNs).max().orElse(0) / 1_000_000.0;
}
public void print() {
System.out.printf("%s: avg=%.2fms, min=%.2fms, max=%.2fms%n",
name, avgMs, minMs, maxMs);
}
}
}
9.8.2 常见操作基准
public class GeometryBenchmarks {
public static void main(String[] args) {
SpatialReference sr = SpatialReference.create(4326);
Polygon polygon = createComplexPolygon(10000); // 10000 顶点
Point point = new Point(0.5, 0.5);
// 缓冲区基准
GeometryBenchmark.benchmark("Buffer",
() -> GeometryEngine.buffer(polygon, sr, 0.01)).print();
// 包含判断基准
GeometryBenchmark.benchmark("Contains",
() -> GeometryEngine.contains(polygon, point, sr)).print();
// 简化基准
GeometryBenchmark.benchmark("Simplify",
() -> GeometryEngine.simplify(polygon, sr)).print();
// 加速后的包含判断
OperatorContains op = OperatorContains.local();
op.accelerateGeometry(polygon, sr,
Geometry.GeometryAccelerationDegree.enumMedium);
GeometryBenchmark.benchmark("Contains (accelerated)",
() -> op.execute(polygon, point, sr, null)).print();
Operator.deaccelerateGeometry(polygon);
}
}
9.9 本章小结
本章详细介绍了 geometry-api-java 的性能优化:
- 几何加速:预处理几何以加速重复查询
- 空间索引:QuadTree、Envelope2DIntersector
- 批量处理:使用 GeometryCursor 流式处理
- 内存优化:对象复用、内存估算、流式处理
- 算法优化:预过滤、简化、分块处理
- 性能监控:计时和内存监控
- 基准测试:性能测量方法
优化建议总结:
- 批量操作使用 GeometryCursor
- 重复查询使用几何加速
- 大数据集使用空间索引
- 始终使用包围盒预过滤
- 监控内存使用避免 OOM
- 进行基准测试验证优化效果

浙公网安备 33010602011771号