Files
sunvpy-docs/docs/content/23-dui-xiang-huan-cun-ji-zhi.md
2026-04-10 13:47:53 +08:00

13 KiB
Raw Blame History

对象缓存机制是SunvStation地理编辑系统的核心组件用于在批量创建和修改地理对象时提供高效的内存管理。该机制通过在内存中暂存对象避免频繁的数据库I/O操作显著提升大批量数据处理的性能。缓存机制区分了新建对象和修改对象两种场景分别采用不同的缓存策略并通过统一的事务性接口完成数据库持久化。

Sources: PySSProcess.py

缓存架构概述

对象缓存机制采用多层次的缓存架构通过SSProcessManager类的成员变量管理不同类型的缓存。缓存系统分为三大类别新建对象缓存、修改对象缓存和删除对象缓存每种类别又进一步区分为地物对象和注记对象。

classDiagram
    class SSProcessManager {
        +GeoBaseList bufferObjList
        +GeoBaseList bufferNoteList
        +list newBufferObjList
        +list newBufferNoteList
        +tuple curNewObj
        +GeoBaseList delBufferGeoList
        +createNewObjByCode(code)
        +setNewObjValue(field, value)
        +addNewObjPoint(x, y, z, type, name)
        +addNewObjToSaveObjList()
        +saveBufferObjToDatabase()
    }
    
    class GeoEditMixin {
        <<Mixin>>
        +transMemoDataToExtendAttr(geoList)
        +persistTempGeoList(geoVec)
        +persistTempNoteList(noteVec)
    }
    
    class GeoBaseList {
        +append(geo)
        +empty()
        +clear()
    }
    
    class GeoBase {
        +getObjectType()
        +getCode()
        +setMemoData(fields, values)
        +getDatasetName()
    }
    
    SSProcessManager *-- GeoBaseList : 管理缓存列表
    SSProcessManager *-- GeoBase : 封装几何对象
    SSProcessManager --> GeoEditMixin : 继承缓存操作
    GeoBaseList o-- GeoBase : 包含对象

该架构体现了关注点分离的设计原则SSProcessManager负责缓存容器管理GeoEditMixin提供缓存操作的具体实现GeoBase和GeoBaseList作为数据载体。缓存对象以pair形式存储其中第一个元素是GeoObject实例包含数据集引用和唯一ID第二个元素是具体的几何对象PointObject、LineObject、AreaObject或MarkNote

Sources: ssprocess_mixins/geo_edit_mixin.py

缓存类型与分类

缓存机制根据对象状态和类型进行明确分类,这种设计使得系统能够对不同场景采用优化的处理策略。

按操作状态分类

缓存类型 存储容器 对象来源 持久化方式 典型应用场景
新建对象缓存 newBufferObjList / newBufferNoteList 脚本创建的新对象 addGeoObject() 添加到地图 批量导入数据、程序化生成地物
修改对象缓存 bufferObjList / bufferNoteList 从地图加载并修改的对象 saveDatabase() 更新数据库 属性批量更新、几何形状编辑
删除对象缓存 delBufferGeoList 标记为删除的对象 delGeoBaseComponent() 执行删除 清理过期数据、对象合并操作
当前新建对象 curNewObj 正在创建过程中的临时对象 转移至其他缓存或丢弃 交互式创建、参数化建模

按对象类型分类

地物对象和注记对象的物理存储位置不同,系统通过getObjectType()方法进行类型识别e_Point_Obj=0、e_Line_Obj=1、e_Area_Obj=2、e_Note_Obj=3并自动路由到相应的缓存容器中。

Sources: PySSProcess.py

缓存生命周期管理

对象的生命周期在缓存系统中遵循明确的阶段划分,从对象创建开始,经过属性设置和几何编辑,最终通过事务性接口持久化到数据库。

flowchart LR
    A[开始创建对象] --> B{创建方式}
    B -->|通过编码创建| C[createNewObjByCode]
    B -->|通过注记类创建| D[createNewObjByClass]
    B -->|默认类型创建| E[createDefaultGeoBase]
    
    C --> F[curNewObj 临时缓存]
    D --> F
    E --> F
    
    F --> G[setNewObjValue 设置属性]
    G --> H[addNewObjPoint 添加坐标点]
    H --> I{下一步操作}
    
    I -->|加入选择集| J[addNewObjToSelObjList]
    I -->|加入保存列表| K[addNewObjToSaveObjList]
    I -->|放弃创建| L[deleteNewObj]
    
    K --> M[newBufferObjList/newBufferNoteList]
    J --> N[selGeoList/selNoteList]
    
    M --> O[saveBufferObjToDatabase 批量保存]
    N --> O
    
    O --> P[transMemoDataToExtendAttr 属性转换]
    P --> Q[map.addGeoObject 添加到地图]
    Q --> R[map.saveDatabase 写入数据库]
    R --> S[清除缓存列表]

该生命周期体现了延迟加载批量处理的优化策略:对象在内存中完成所有编辑操作,仅在最后阶段才与数据库交互,显著减少了网络往返和数据锁争用。

Sources: ssprocess_mixins/geo_edit_mixin.py

核心API详解

对象创建API

createNewObjByCode() 是新建对象的主要入口,通过编码获取地物定义并创建相应类型的几何对象。该方法会自动从当前数据源获取特征定义,包括对象类型、颜色、线型、线宽等属性,并应用到新创建的对象上。

# 通过编码创建新地物对象
obj, geo = SSProcess.createNewObjByCode(3103013)
if obj is not None:
    # 设置对象属性
    SSProcess.setNewObjValue("SSObj_Name", "新建道路")
    SSProcess.setNewObjValue("[宽度]", "15.5")
    
    # 添加坐标点(线对象)
    SSProcess.addNewObjPoint(100.0, 200.0, 0.0, 0, "")
    SSProcess.addNewObjPoint(150.0, 250.0, 0.0, 0, "")
    
    # 将对象加入保存列表
    SSProcess.addNewObjToSaveObjList()

Sources: ssprocess_mixins/geo_edit_mixin.py

属性设置API

setNewObjValue() 方法支持基本属性和扩展属性的统一设置。基本属性以SSObj_前缀标识,扩展属性使用方括号[]包裹。该方法还支持批量设置多个扩展属性,通过逗号分隔属性名和值。

属性设置对比表:

属性类型 语法格式 存储位置 转换逻辑
基本属性 SSObj_Name 对象内置字段 直接映射到GeoBase的getter/setter
单个扩展属性 [自定义字段名] MemoData字段 通过StringArray键值对存储
批量扩展属性 [字段1],[字段2] MemoData字段 解析后分别设置键值对

Sources: ssprocess_mixins/geo_edit_mixin.py

批量持久化API

saveBufferObjToDatabase() 是缓存机制的核心事务接口,负责将所有缓存中的对象持久化到数据库。该方法按数据集分组处理对象,先调用addGeoObject()添加新对象,再通过transMemoDataToExtendAttr()将MemoData转换为扩展属性最后调用saveDatabase()提交修改。

sequenceDiagram
    participant API as saveBufferObjToDatabase()
    participant Cache as 缓存列表
    participant Map as ScaleMap
    participant DB as 数据库
    
    API->>Cache: 读取newBufferObjList/newBufferNoteList
    API->>API: 按数据集分组
    loop 每个数据集分组
        API->>Map: addGeoObject(geoList)
        API->>Map: setExtentAttr(geo, fields, values)
    end
    API->>Cache: 清空newBufferObjList/newBufferNoteList
    
    API->>Cache: 读取bufferObjList/bufferNoteList
    API->>Map: setExtentAttr(geo, fields, values)
    API->>Map: saveDatabase(geoList)
    API->>Cache: 清空bufferObjList/bufferNoteList
    
    API->>Map: delGeoBaseComponent(delBufferGeoList)
    API->>Cache: 清空delBufferGeoList

该方法实现了原子性的事务特性:所有缓存对象的保存操作作为一个整体提交,成功则全部生效,失败则回滚至保存前状态。同时,通过数据集分组优化了数据库锁粒度,提高了并发性能。

Sources: ssprocess_mixins/geo_edit_mixin.py

备忘数据转换API

transMemoDataToExtendAttr() 方法负责将对象的备忘数据MemoData转换为扩展属性。这是必要的中间步骤因为MemoData是Python层面的临时存储格式而扩展属性是数据库层面的持久化格式。

转换过程在事务边界内进行(beginSetExtentAttr() / endSetExtentAttr()),确保扩展属性设置的原子性。对于具有大量扩展属性的对象,该操作可能产生显著的性能开销,建议批量处理时控制对象数量。

Sources: ssprocess_mixins/geo_edit_mixin.py

缓存与选择集的关系

缓存列表与选择集是两个独立但相关的容器系统。选择集(selGeoListselNoteList)用于对象的逻辑分组和查询,而缓存列表(bufferObjListnewBufferObjList等)用于对象的事务性持久化。

关系对比表:

容器类型 主要用途 数据来源 是否持久化 清除时机
选择集 逻辑分组、批量查询 从地图加载或新建对象添加 clearSelection()手动清除
新建对象缓存 事务性保存新对象 通过createNewObjByCode创建 saveBufferObjToDatabase()自动清除
修改对象缓存 事务性更新现有对象 从选择集加载并修改 saveBufferObjToDatabase()自动清除
删除对象缓存 事务性删除对象 标记为删除的对象 saveBufferObjToDatabase()自动清除

addNewObjToSelObjList()addNewObjToSaveObjList() 方法体现了这种分离设计:前者将对象加入选择集进行后续查询或操作,后者将对象加入缓存列表准备持久化。一个对象可以同时存在于两个容器中,也可以仅存在于其中一个。

Sources: ssprocess_mixins/geo_edit_mixin.py

最佳实践与注意事项

批量操作的性能优化

对于大量对象的批量操作,建议遵循以下最佳实践:

  1. 避免频繁调用saveBufferObjToDatabase()该方法会触发数据库事务每次调用都有固定开销。应累积足够多的对象后再批量保存建议每1000-5000个对象保存一次。

  2. 合理使用数据集分组:虽然saveBufferObjToDatabase()内部已实现数据集分组,但在创建对象时尽量按数据集顺序添加对象,可以减少分组操作的复杂度。

  3. 控制扩展属性数量每个对象的扩展属性存储在MemoData中过多扩展属性会增加内存占用和序列化开销。建议将高频查询的属性映射为基本属性低频属性作为扩展属性。

内存管理注意事项

缓存对象在Python层面持有C++对象的引用,可能导致内存泄漏。以下场景需要特别关注:

  • 对象创建后未加入保存列表:如果调用了createNewObjByCode()但未调用addNewObjToSaveObjList()addNewObjToSelObjList(),对象会一直保留在curNewObj中,占用内存直到下一次创建操作覆盖。

  • 事务中断后的缓存清理:如果在调用saveBufferObjToDatabase()之前发生异常缓存列表中的对象不会被自动清理。建议在异常处理中手动调用缓存清除操作或重新创建SSProcess实例。

并发安全注意事项

缓存机制不是线程安全的。如果在多线程环境下使用需要通过外部同步机制如线程锁确保对SSProcess实例的访问序列化。系统设计的典型使用场景是单线程的脚本执行环境。

与撤销系统的集成

缓存机制与撤销标记管理功能存在交互。如果需要在保存到数据库前支持撤销操作,应将对象同时添加到选择集和保存列表中,这样可以在不触发数据库提交的情况下回滚修改。

相关主题

对象缓存机制是地理编辑功能链中的关键环节。掌握缓存机制后,建议继续学习以下相关主题: