第16章-性能优化与最佳实践
第16章:性能优化与最佳实践
16.1 数据优化
16.1.1 空间索引
// ShapeFile 启用空间索引
var provider = new ShapeFile("data.shp", true, true); // 启用空间索引
// PostGIS 确保有空间索引
// CREATE INDEX idx_geom ON table USING GIST(geom);
// SQL Server 空间索引
// CREATE SPATIAL INDEX idx_geom ON table(geom);
16.1.2 数据简化
using NetTopologySuite.Simplify;
// 简化几何(按比例尺)
public static Geometry SimplifyByScale(Geometry geometry, double scale)
{
// 根据比例尺计算容差
double tolerance = 1 / scale * 0.5; // 0.5mm 在地图上
return TopologyPreservingSimplifier.Simplify(geometry, tolerance);
}
// 简化后的数据提供者
public class SimplifiedProvider : IProvider
{
private readonly IProvider _innerProvider;
private readonly double _tolerance;
public Collection<Geometry> GetGeometriesInView(Envelope envelope)
{
var geometries = _innerProvider.GetGeometriesInView(envelope);
return new Collection<Geometry>(
geometries.Select(g => TopologyPreservingSimplifier.Simplify(g, _tolerance)).ToList());
}
}
16.1.3 数据分级
// 按比例尺使用不同精度的数据
public class MultiResolutionProvider : IProvider
{
private readonly Dictionary<double, IProvider> _providers;
public void SetProvider(double maxScale, IProvider provider)
{
_providers[maxScale] = provider;
}
public Collection<Geometry> GetGeometriesInView(Envelope envelope, double scale)
{
var provider = _providers
.Where(p => p.Key >= scale)
.OrderBy(p => p.Key)
.First()
.Value;
return provider.GetGeometriesInView(envelope);
}
}
16.2 渲染优化
16.2.1 图层缓存
public class CachedVectorLayer : VectorLayer
{
private Bitmap _cache;
private Envelope _cacheEnvelope;
private double _cacheZoom;
public override void Render(Graphics g, Map map)
{
// 检查缓存是否有效
if (_cache != null &&
_cacheEnvelope.Equals(map.Envelope) &&
Math.Abs(_cacheZoom - map.Zoom) < 0.001)
{
g.DrawImage(_cache, 0, 0);
return;
}
// 渲染到缓存
_cache?.Dispose();
_cache = new Bitmap(map.Size.Width, map.Size.Height);
using (var cacheGraphics = Graphics.FromImage(_cache))
{
cacheGraphics.Clear(Color.Transparent);
base.Render(cacheGraphics, map);
}
_cacheEnvelope = map.Envelope;
_cacheZoom = map.Zoom;
g.DrawImage(_cache, 0, 0);
}
public void InvalidateCache()
{
_cache?.Dispose();
_cache = null;
}
}
16.2.2 异步渲染
public class AsyncMapRenderer
{
private readonly Map _map;
private CancellationTokenSource _cts;
public event Action<Image> MapRendered;
public event Action<Exception> RenderError;
public async Task RenderAsync()
{
_cts?.Cancel();
_cts = new CancellationTokenSource();
try
{
var image = await Task.Run(() =>
{
_cts.Token.ThrowIfCancellationRequested();
return _map.GetMap();
}, _cts.Token);
MapRendered?.Invoke(image);
}
catch (OperationCanceledException)
{
// 渲染被取消
}
catch (Exception ex)
{
RenderError?.Invoke(ex);
}
}
}
16.2.3 裁剪优化
// 启用图层裁剪
vectorLayer.ClippingEnabled = true;
// 只渲染可见区域
public override void Render(Graphics g, Map map)
{
// 设置裁剪区域
g.SetClip(new Rectangle(0, 0, map.Size.Width, map.Size.Height));
// 只查询可见区域的数据
var visibleGeometries = DataSource.GetGeometriesInView(map.Envelope);
// 渲染...
}
16.3 内存优化
16.3.1 资源释放
// 正确释放资源
public class MapManager : IDisposable
{
private Map _map;
private List<ILayer> _layers;
public void Dispose()
{
// 释放图层
foreach (var layer in _layers)
{
if (layer is IDisposable disposable)
{
disposable.Dispose();
}
}
_layers.Clear();
// 释放地图
_map?.Dispose();
_map = null;
}
}
// 使用 using 语句
using (var map = new Map(new Size(800, 600)))
{
// 使用地图...
using (var image = map.GetMap())
{
image.Save("output.png");
}
}
16.3.2 对象池
public class GeometryPool
{
private readonly ConcurrentBag<Geometry> _pool;
private readonly GeometryFactory _factory;
private readonly int _maxSize;
public GeometryPool(int maxSize = 1000)
{
_pool = new ConcurrentBag<Geometry>();
_factory = new GeometryFactory();
_maxSize = maxSize;
}
public Point GetPoint(Coordinate coordinate)
{
if (_pool.TryTake(out var geometry) && geometry is Point point)
{
// 重用对象(需要几何支持可变)
return point;
}
return _factory.CreatePoint(coordinate);
}
public void Return(Geometry geometry)
{
if (_pool.Count < _maxSize)
{
_pool.Add(geometry);
}
}
}
16.3.3 数据分页
public class PaginatedProvider : IProvider
{
private readonly IProvider _innerProvider;
private readonly int _pageSize;
public void ExecuteIntersectionQuery(Envelope envelope, FeatureDataSet ds)
{
// 获取所有ID
var ids = _innerProvider.GetObjectIDsInView(envelope);
// 分页获取数据
for (int i = 0; i < ids.Count; i += _pageSize)
{
var pageIds = ids.Skip(i).Take(_pageSize);
foreach (var id in pageIds)
{
var feature = _innerProvider.GetFeature(id);
// 处理要素...
}
// 可选:触发进度回调
}
}
}
16.4 网络优化
16.4.1 瓦片缓存
public class TileCacheManager
{
private readonly MemoryCache<byte[]> _memoryCache;
private readonly FileCache _fileCache;
public async Task<byte[]> GetTileAsync(TileIndex index, Func<Task<byte[]>> fetcher)
{
// 1. 检查内存缓存
var tile = _memoryCache.Find(index);
if (tile != null)
return tile;
// 2. 检查文件缓存
tile = _fileCache.Find(index);
if (tile != null)
{
_memoryCache.Add(index, tile);
return tile;
}
// 3. 从网络获取
tile = await fetcher();
// 4. 保存到缓存
_fileCache.Add(index, tile);
_memoryCache.Add(index, tile);
return tile;
}
}
16.4.2 请求合并
public class BatchTileLoader
{
private readonly SemaphoreSlim _semaphore;
private readonly HttpClient _httpClient;
public BatchTileLoader(int maxConcurrent = 4)
{
_semaphore = new SemaphoreSlim(maxConcurrent);
_httpClient = new HttpClient();
}
public async Task<Dictionary<TileIndex, byte[]>> LoadTilesAsync(
IEnumerable<TileIndex> indices, Func<TileIndex, string> urlBuilder)
{
var tasks = indices.Select(async index =>
{
await _semaphore.WaitAsync();
try
{
var url = urlBuilder(index);
var data = await _httpClient.GetByteArrayAsync(url);
return (index, data);
}
finally
{
_semaphore.Release();
}
});
var results = await Task.WhenAll(tasks);
return results.ToDictionary(r => r.index, r => r.data);
}
}
16.5 最佳实践
16.5.1 图层组织
// 推荐的图层顺序(从下到上)
// 1. 背景图层(瓦片底图)
map.BackgroundLayer.Add(tileLayer);
// 2. 栅格图层
map.Layers.Add(rasterLayer);
// 3. 面图层
map.Layers.Add(polygonLayer);
// 4. 线图层
map.Layers.Add(lineLayer);
// 5. 点图层
map.Layers.Add(pointLayer);
// 6. 标注图层
map.Layers.Add(labelLayer);
// 7. 高亮/临时图层
map.Layers.Add(highlightLayer);
16.5.2 样式配置
// 使用样式工厂
public static class StyleFactory
{
public static VectorStyle CreatePolygonStyle(Color fill, Color outline, float width = 1)
{
return new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(150, fill)),
Outline = new Pen(outline, width),
EnableOutline = true
};
}
public static VectorStyle CreateLineStyle(Color color, float width)
{
return new VectorStyle
{
Line = new Pen(color, width)
{
LineJoin = LineJoin.Round,
StartCap = LineCap.Round,
EndCap = LineCap.Round
}
};
}
public static VectorStyle CreatePointStyle(Color color, float size)
{
return new VectorStyle
{
PointColor = new SolidBrush(color),
PointSize = size
};
}
}
16.5.3 错误处理
public class SafeMapRenderer
{
private readonly Map _map;
private readonly ILogger _logger;
public Image RenderMap()
{
try
{
return _map.GetMap();
}
catch (Exception ex)
{
_logger.LogError(ex, "地图渲染失败");
// 返回错误图片
return CreateErrorImage("渲染失败: " + ex.Message);
}
}
private Image CreateErrorImage(string message)
{
var bitmap = new Bitmap(_map.Size.Width, _map.Size.Height);
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(Color.LightGray);
g.DrawString(message, new Font("Arial", 12), Brushes.Red, 10, 10);
}
return bitmap;
}
}
16.5.4 配置管理
// appsettings.json
{
"SharpMap": {
"DataPath": "Data",
"CachePath": "Cache",
"DefaultSRID": 4326,
"MaxZoom": 1000000,
"MinZoom": 0.001,
"TileCache": {
"MemorySize": 500,
"FileEnabled": true,
"Expiration": "24:00:00"
}
}
}
// 配置类
public class SharpMapOptions
{
public string DataPath { get; set; }
public string CachePath { get; set; }
public int DefaultSRID { get; set; }
public double MaxZoom { get; set; }
public double MinZoom { get; set; }
public TileCacheOptions TileCache { get; set; }
}
16.6 性能监控
public class MapPerformanceMonitor
{
private readonly Stopwatch _stopwatch = new Stopwatch();
private readonly ILogger _logger;
public T MeasureOperation<T>(string operationName, Func<T> operation)
{
_stopwatch.Restart();
var result = operation();
_stopwatch.Stop();
_logger.LogInformation(
"{Operation} 耗时: {ElapsedMs}ms",
operationName,
_stopwatch.ElapsedMilliseconds);
return result;
}
public void LogMemoryUsage()
{
var process = Process.GetCurrentProcess();
_logger.LogInformation(
"内存使用: {WorkingSet}MB, GC: {GC0}/{GC1}/{GC2}",
process.WorkingSet64 / 1024 / 1024,
GC.CollectionCount(0),
GC.CollectionCount(1),
GC.CollectionCount(2));
}
}
16.7 本章小结
本章介绍了 SharpMap 的性能优化和最佳实践:
- 数据优化:空间索引、数据简化、数据分级
- 渲染优化:图层缓存、异步渲染、裁剪优化
- 内存优化:资源释放、对象池、数据分页
- 网络优化:瓦片缓存、请求合并
- 最佳实践:图层组织、样式配置、错误处理
- 性能监控:操作计时、内存监控
下一章预告:第17章将通过实战案例展示 SharpMap 的综合应用。

浙公网安备 33010602011771号