第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 的性能优化和最佳实践:

  1. 数据优化:空间索引、数据简化、数据分级
  2. 渲染优化:图层缓存、异步渲染、裁剪优化
  3. 内存优化:资源释放、对象池、数据分页
  4. 网络优化:瓦片缓存、请求合并
  5. 最佳实践:图层组织、样式配置、错误处理
  6. 性能监控:操作计时、内存监控

下一章预告:第17章将通过实战案例展示 SharpMap 的综合应用。

posted @ 2026-01-08 14:09  我才是银古  阅读(0)  评论(0)    收藏  举报