python 单例

45 阅读2分钟

问题分析

是的,当前的代码设计确实会导致创建很多session,这会带来以下问题:

  1. 资源浪费:每次调用都会创建新的session连接,消耗系统资源
  2. 性能下降:频繁建立和关闭连接会增加网络开销和延迟
  3. 连接池耗尽:IoTDB服务器的连接数有限,过多连接可能导致连接池耗尽
  4. 内存泄漏风险:如果session没有正确关闭,可能导致内存泄漏

修复建议

方案一:使用上下文管理器(推荐)

from contextlib import contextmanager

@contextmanager
def get_session():
    session = Session(
        host=settings.iotDB_host,
        port=settings.iotDB_port,
        user=settings.iotDB_username,
        password=settings.iotDB_password,
        zone_id="UTC+8"
    )
    try:
        session.open(False)
        yield session
    finally:
        session.close()

# 修改使用session的函数
def set_record_data(time, measurement: str, measurement_value: float):
    try:
        if measurement == '':
            return None
        
        with get_session() as session:
            session.insert_record(
                device_id="root.dt.plc",  # 设备路径
                timestamp=int(time),  # 时间戳
                measurements=[measurement],  # 测量值列表
                data_types=[TSDataType.DOUBLE],  # 类型列表
                values=[measurement_value]  # 值列表
            )
        return True
    except Exception as e:
        print("数据记录赋值异常" + str(e))
        return False

方案二:使用单例模式管理session

class IoTDBSessionManager:
    _instance = None
    _session = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def get_session(self):
        if self._session is None or not self._session.is_open():
            self._session = Session(
                host=settings.iotDB_host,
                port=settings.iotDB_port,
                user=settings.iotDB_username,
                password=settings.iotDB_password,
                zone_id="UTC+8"
            )
            self._session.open(False)
        return self._session
    
    def close_session(self):
        if self._session and self._session.is_open():
            self._session.close()
            self._session = None

# 使用单例管理器
def set_record_data(time, measurement: str, measurement_value: float):
    try:
        if measurement == '':
            return None
        
        session_manager = IoTDBSessionManager()
        session = session_manager.get_session()
        
        session.insert_record(
            device_id="root.dt.plc",
            timestamp=int(time),
            measurements=[measurement],
            data_types=[TSDataType.DOUBLE],
            values=[measurement_value]
        )
        return True
    except Exception as e:
        print("数据记录赋值异常" + str(e))
        return False

方案三:在应用启动时初始化session(适用于长时间运行的服务)

# 全局session变量
_global_session = None

def init_global_session():
    global _global_session
    if _global_session is None:
        _global_session = Session(
            host=settings.iotDB_host,
            port=settings.iotDB_port,
            user=settings.iotDB_username,
            password=settings.iotDB_password,
            zone_id="UTC+8"
        )
        _global_session.open(False)

def get_global_session():
    global _global_session
    if _global_session is None or not _global_session.is_open():
        init_global_session()
    return _global_session

def close_global_session():
    global _global_session
    if _global_session and _global_session.is_open():
        _global_session.close()
        _global_session = None

# 使用全局session
def set_record_data(time, measurement: str, measurement_value: float):
    try:
        if measurement == '':
            return None
        
        session = get_global_session()
        session.insert_record(
            device_id="root.dt.plc",
            timestamp=int(time),
            measurements=[measurement],
            data_types=[TSDataType.DOUBLE],
            values=[measurement_value]
        )
        return True
    except Exception as e:
        print("数据记录赋值异常" + str(e))
        return False

推荐使用方案一(上下文管理器),因为它既保证了资源的正确释放,又避免了连接的频繁创建和销毁。