def __init__(self, client_para: dict = None, **kwargs): """ 创建SocketIO简单客户端 @param {dict} client_para - 客户端创建参数,参考python-socketio的创建参数 """ self.client_para = client_para if client_para is not None else {} self.socketio = socketio.Client(**self.client_para) self._thread = None # 客户端连接等待线程 self.bg_task_para = dict() # 连接成功后的后台执行参数 self.bg_emit_queue = MemoryQueue() # 后台发送数据的公共队列
class SocketIOClient(object): """ SocketIO简单客户端 """ ############################# # 构造函数 ############################# def __init__(self, client_para: dict = None, **kwargs): """ 创建SocketIO简单客户端 @param {dict} client_para - 客户端创建参数,参考python-socketio的创建参数 """ self.client_para = client_para if client_para is not None else {} self.socketio = socketio.Client(**self.client_para) self._thread = None # 客户端连接等待线程 self.bg_task_para = dict() # 连接成功后的后台执行参数 self.bg_emit_queue = MemoryQueue() # 后台发送数据的公共队列 def __del__(self): """ 析构函数 """ if self.socketio.connected: try: # 断开连接 self.disconnect() except: pass ############################# # 公共函数 ############################# def connect(self, url: str, headers={}, transports=None, namespaces=None, socketio_path='socket.io', is_asyn: bool = False): """ 连接服务器 @param {str} url - 要连接的url地址, 例如'http://localhost:5000' @param {bool} is_asyn=False - 是否异步处理, 如果是则直接返回 """ if self.socketio.connected: raise RuntimeError('Client is already connected!') # 执行连接 self.socketio.connect(url, headers=headers, transports=transports, namespaces=namespaces, socketio_path=socketio_path) if is_asyn: # 异步模式 self._thread = threading.Thread(target=self.socketio.wait, name='Socketio-client-wait-thread') self._thread.setDaemon(True) self._thread.start() else: # 同步模式, 等待连接中断 self.socketio.wait() def disconnect(self): """ 关闭连接 """ if not self.socketio.connected: raise RuntimeError('Client is not connect!') # 尝试结束连接的后台线程 try: _thread = self.bg_task_para.get('bg_thread', None) if _thread is not None: RunTool.stop_thread(_thread) except: pass # 清空所有待发送数据 self.bg_emit_queue.clear() # 断开连接 self.socketio.disconnect() def bind_on_event(self, event: str, func, namespace: str = None): """ 绑定指定函数为特定事件的处理函数 @param {str} event - 事件名, 其中一些事件是标准事件, 例如: 'connect' - 连接事件 'disconnect' - 断开连接事件 @param {function} func - 处理函数对象 @param {str} namespace=None - 命名空间,例如'/test' """ self.socketio.on(event, handler=func, namespace=namespace) def bind_bg_task_on_connected(self, task_func, before_func=None, namespace: str = None): """ 绑定连接成功后的后台任务 注:只支持注册一个 @param {function} task_func - 后台执行任务函数,如果是永久运行,需自行实现循环逻辑 @param {function} before_func=None - 执行后台任务前需执行的操作函数 @param {str} namespace=None - 命名空间,例如'/test' """ self.bg_task_para = { 'task_func': task_func, 'before_func': before_func, 'lock': threading.Lock() } self.socketio.on('connect', handler=self._bg_task_on_connected_func, namespace=namespace) def emit(self, event, data=None, namespace=None, callback=None): """ 向服务器发送信息 注意:该函数必须在绑定事件的函数内部使用 @param {str} event - 事件名 @param {dict} data - 要通知的数据字典 @param {str} namespace='/' - 命名空间 @param {function} callback=None - 回调函数 注:服务端的return值将作为回调函数的入参 """ self.socketio.emit(event, data=data, namespace=namespace, callback=callback) def emit_bg(self, event, data=None, namespace=None): """ 后台向服务器发送信息 注:必须设置了emit_bg_task作为后台服务才可以支持 @param {str} event - 事件名 @param {dict} data - 要通知的数据字典 @param {str} namespace='/' - 命名空间 """ self.bg_emit_queue.put([event, data, namespace]) def emit_bg_task(self): """ 后台向服务器发送信息的线程函数 注:该函数不可单独调用,用于bind_bg_task_on_connected函数的后台函数, 监控队列并将送入队列的数据发往服务器 """ while True: try: # 从队列获取数据 _data = self.bg_emit_queue.get() # 向服务器提交数据 self.emit(_data[0], data=_data[1], namespace=_data[2]) except queue.Empty: # 队列为空 gevent.sleep(0.1) ############################# # 内部函数 ############################# def _bg_task_on_connected_func(self): """ 连接时的后台服务 """ if self.bg_task_para['before_func'] is not None: # 执行前面的函数 self.bg_task_para['before_func']() # 限制只能启动一个 with self.bg_task_para['lock']: self.bg_task_para[ 'bg_thread'] = self.socketio.start_background_task( self.bg_task_para['task_func'])
class ConnectionPoolFw(ABC): """ 连接池处理框架类 抽象连接池的公共方法形成框架,并提供基本的处理功能,简化连接池编程的难度 """ ############################# # 私有变量 ############################# _logger = None # 日志对象 _current_size = 0 # 当前连接池大小 _access_lock = None # 访问连接池对象的线程锁 # 连接池连接信息,以字典的方式记录每个连接的情况 # key - 连接对象的id(str(uuid.uuid1())) # value - 连接对象属性,为一个NullObj对象,属性定义如下 # .connection - 连接对象本身 # .is_using {bool} - 是否正被使用 # .last_free_time {datetime} - 上一次释放的时间 # .last_test_time {datetime} - 上一次检查有效性的时间 _connection_pool = None # 空闲连接池,以队列方式实现,使用MemoryQueue的后进先出模式,仅登记连接对象的id # 注意空闲池中的id有可能已被释放,因此取出来要判断对象是否还存在 _free_pool = None _is_destroyed = False # 标识连接池是否已被销毁 _daemon_running = False # 标识守护线程是否在执行 ############################# # 公共属性 ############################# connect_para = None name = 'ConnectionPool' maxsize = 100 minsize = 0 realse_free_time = 300 test_on_get = False test_on_free = False test_while_idle = True test_idle_time = 60 validation_query = '' get_connection_timeout = 0 daemon_sleep_time = 1 @property def is_destroyed(self): """ 返回连接池是否已被销毁的标记 @property {bool} """ return self._is_destroyed @property def current_size(self): """ 返回池子大小 @property {int} """ return self._current_size @property def free_pool_size(self): """ 返回空闲池大小 @property {int} """ return self._free_pool.qsize() ############################# # 公共函数 ############################# def __init__(self, connect_para, name='ConnectionPool', maxsize=100, minsize=0, realse_free_time=300, test_on_get=False, test_on_free=False, test_while_idle=True, test_idle_time=60, validation_query='', get_connection_timeout=0, logger=None, init_break_if_connect_error=True, daemon_sleep_time=1): """ 构造函数,创建连接池 @param {NullObj} connect_para - 连接参数,具体参数属性根据实现类指定 @param {string} name='ConnectionPool' - 连接池名称 @param {int} maxsize=100 - 最大连接数 @param {int} minsize=0 - 最小保持连接数 @param {number} realse_free_time=300 - 自动释放多长时间的空闲无操作连接(单位秒) @param {bool} test_on_get=False - 是否在获取连接前检查连接是否有效 @param {bool} test_on_free=False - 是否在归还连接时检查连接是否有效 @param {bool} test_while_idle=True - 是否检查空闲连接是否有效 @param {number} test_idle_time=60 - 自动检查空闲连接有效性的时间间隔(单位秒) @param {string} validation_query='' - 检查连接是否有效的查询语句(非数据库类的可以传入检查参数) @param {number} get_connection_timeout=0 - 获取连接的等待超时时间(单位秒),0代表不超时 @param {Logger} logger=None - 日志对象,服务过程中通过该函数写日志: 可以为标准的logging日志库对象,也可以为simple_log对象,但要求对象实现: 标准的info、debug、warning、error、critical五个日志方法 @param {bool} init_break_if_connect_error=True - 如果连接失败则初始化抛出异常 @param {number} daemon_sleep_time=1 - 守护进程的间隔刷新时间(单位秒) """ # 设置初始化参数 self.connect_para = connect_para self.name = name self.maxsize = maxsize self.minsize = minsize self.realse_free_time = realse_free_time self.test_on_get = test_on_get self.test_on_free = test_on_free self.test_while_idle = test_while_idle self.test_idle_time = test_idle_time self.validation_query = validation_query self.get_connection_timeout = get_connection_timeout self._logger = logger self.daemon_sleep_time = daemon_sleep_time # 应在__init__中初始化,否则会出现两个实例对象引用地址一样的问题 self._connection_pool = dict() self._free_pool = MemoryQueue(queue_type=EnumQueueType.LIFO, maxsize=0) self._access_lock = threading.Lock() # 按最小保持连接数创建连接 _i = 0 while _i < self.minsize: try: # 创建连接出现异常记录日志,并抛出异常 with ExceptionTool.ignored( expect=(), logger=self._logger, self_log_msg='Connection Pool [%s] Init Error ' % (self.name), force_log_level=logging.ERROR ): # 创建连接 _cid = self._create_connection() # 把连接加入到空闲池 self._free_pool.put(_cid) self._current_size += 1 except Exception as e: # 根据init_break_if_connect_error参数,如果为False则连接异常也继续处理 if init_break_if_connect_error: raise e _i += 1 # 创建守护线程,负责检查及释放空闲连接 _daemon_thread = threading.Thread( target=self.__start_daemon_thread_fun, args=(1,), name='DaemonThread-ConnectionPool[%s]' % (self.name) ) _daemon_thread.setDaemon(True) self._daemon_running = True _daemon_thread.start() def get_connection(self): """ 获取一个可用连接(从空闲池获取) @return {object} - 返回连接对象,具体类型由实现类定义 注意:该对象会有一个connection_pool_id的属性,用于释放连接时使用 @throws {TimeoutError} - 如果超时则会抛出该异常 @throws {NameError} - 如果对象被销毁后再访问,会抛出该异常 """ _begin_time = datetime.datetime.now() while True: if self._is_destroyed: # 线程池已销毁,抛出异常 raise NameError # 为了控制超时,所以用循环处理,先获取访问权 if self._access_lock.acquire(blocking=True, timeout=0.1): # 获取锁成功 _cid = '' # 登记获取到的连接id _is_create_connection = False # 标识是否新建的连接 try: # 先尝试从空闲池获取连接 try: _cid = self._free_pool.get_nowait() except Empty: pass if _cid == '': # 没有空闲连接,需要创建一个新连接进行处理,考虑效率问题不在锁定状态做 if self._current_size < self.maxsize: _is_create_connection = True self._current_size += 1 # 为避免连接数超过限制,这里要先增加当前数量 else: # 获取到空闲连接,标记被占用 self._connection_pool[_cid].is_using = True finally: self._access_lock.release() # 如果需要创建新连接 if _is_create_connection: try: _cid = self._create_connection() except Exception as e: # 创建连接出现异常,当前数量恢复 self._access_lock.acquire() self._current_size -= 1 self._access_lock.release() # 记录日志 if self._logger is not None: self._logger.log( logging.ERROR, '[EX:%s]Create new connection error: %s ' % ( str(type(e)), traceback.format_exc() ) ) # 抛出异常 raise sys.exc_info()[1] # 设置连接被占用 self._connection_pool[_cid].is_using = True # 校验连接有效性,只有创建了连接才这样处理,注意有可能释放了,但id还在空闲队列的情况 if _cid != '' and _cid in self._connection_pool.keys(): if self.test_on_get: if self.test_connection(self._connection_pool[_cid].connection): # 连接有效,直接返回 return self._connection_pool[_cid].connection else: # 连接无效,释放连接,同时继续下一次循环 _connection = self._connection_pool[_cid].connection del self._connection_pool[_cid] self._close_connection(_connection) # 当前线程数量恢复 self._access_lock.acquire() self._current_size -= 1 self._access_lock.release() if self._logger is not None: self._logger.log( logging.DEBUG, 'Connection Pool [%s] get connection test false, release connection [%s]' % ( self.name, _cid ) ) else: # 返回连接 return self._connection_pool[_cid].connection # 判断是否已超时;如果get_connection_timeout <= 0则会一直阻塞直到异常 if self.get_connection_timeout > 0 and (datetime.datetime.now() - _begin_time).total_seconds() > self.get_connection_timeout: # 已超时,抛出异常 raise TimeoutError('get_connection timeout!') def free_connection(self, connection): """ 释放所使用的连接对象(放回空闲池) @param {object} connection - 要释放的连接对象 """ _cid = connection.connection_pool_id if self._is_destroyed or _cid not in self._connection_pool.keys() or not self._connection_pool[_cid].is_using: # 对象已销毁,或连接对象不在池中或状态不正确,不处理 return # 判断是否有效 _is_realse = False if self.test_on_free: if not self.test_connection(connection): # 状态无效,删除该对象 self._access_lock.acquire() try: self._current_size -= 1 del self._connection_pool[_cid] _is_realse = True finally: self._access_lock.release() # 进行最终处理 if _is_realse: # 释放对象 self._close_connection(connection) if self._logger is not None: self._logger.log( logging.DEBUG, 'Connection Pool [%s] free connection test false, release connection [%s]' % ( self.name, _cid ) ) else: # 放回空闲队列(线程安全,无需锁处理) self._connection_pool[_cid].is_using = False self._free_pool.put(_cid) def test_connection(self, connection): """ 检查指定的连接有效性 @param {object} connection - 要检查的连接对象 @return {bool} - 测试结果 """ try: # 执行不抛出异常就是成功 self._test_connection_self(connection) return True except Exception as e: if self._logger is not None: self._logger.log( logging.ERROR, '[EX:%s]Connection Pool [%s] test connection [%s] error:\n%s' % ( str(type(e)), self.name, connection.connection_pool_id, traceback.format_exc() ) ) return False def reconnect(self, connection): """ 对指定对象重新进行连接 @param {object} connection - 要重新连接的对象 @return {object} - 返回有效的连接对象 @throws {Exception} - 当重连失败时应抛出异常 """ with ExceptionTool.ignored( expect=(), logger=self._logger, self_log_msg='Connection Pool [%s] reconnect[%s] Error ' % ( self.name, connection.connection_pool_id), force_log_level=logging.ERROR ): _cid = connection.connection_pool_id _new_connection = self._reconnect_self(connection) _new_connection.connection_pool_id = _cid self._connection_pool[_cid].connection = _new_connection def destroy(self): """ 销毁连接池并释放资源 注意连接池销毁后将不能再使用 """ # 设置标记 self._is_destroyed = True # 等待守护线程结束 while self._daemon_running: RunTool.sleep(0.5) # 清除所有线程连接资源 self._access_lock.acquire() try: self._current_size = 0 self._free_pool.clear() for (_key, _value) in self._connection_pool.items(): # 逐个关闭连接 self._close_connection(_value.connection) self._connection_pool.clear() finally: self._access_lock.release() def __del__(self): """ 销毁对象的处理 """ self.destroy() ############################# # 内部函数 ############################# def _create_connection(self): """ 创建一个新的连接对象 @return {string} - 返回连接对象的id @throws {Exception} - 当创建失败或连接无效时应直接抛出异常 """ # 调用实现类创建新的连接对象 _connection = self._create_connection_self() _cid = str(uuid.uuid1()) _connection.connection_pool_id = _cid # 生成内部的连接信息对象 _connection_info = NullObj() _connection_info.connection = _connection _connection_info.is_using = False _connection_info.last_free_time = datetime.datetime.now() _connection_info.last_test_time = datetime.datetime.now() # 放入连接池 self._connection_pool[_cid] = _connection_info # 返回连接id return _cid def _close_connection(self, connection): """ 关闭连接(出现异常只记录日志不抛出异常) @param {object} connection - 要关闭的连接对象 """ with ExceptionTool.ignored_all( unexpect=(), logger=self._logger, self_log_msg='Connection Pool [%s] close connection[%s] error:' % ( self.name, connection.connection_pool_id), force_log_level=logging.ERROR ): self._close_connection_self(connection) def __start_daemon_thread_fun(self, tid): """ 守护线程,负责检查连接有效性和释放连接 @param {int} tid - 线程id """ while True: if self._is_destroyed: # 出现销毁标记,退出守护 break with ExceptionTool.ignored_all( unexpect=(), logger=self._logger, self_log_msg='Connection Pool [%s] DaemonThread[%s] Error ' % (self.name, str(tid)), force_log_level=logging.ERROR ): # 遍历连接进行处理,从空闲队列中逐个拿出来进行确认,没有问题再放回去 _count = self._free_pool.qsize() while _count > 0: try: _key = self._free_pool.get_nowait() _count -= 1 # 取出一个减少一次计数,避免无限循环 except Empty: # 没有空闲连接,不用处理,退出循环 break # 开始进行判断处理 _value = self._connection_pool[_key] if self._is_destroyed: # 出现销毁标记,退出守护 break _is_realse = False self._access_lock.acquire() try: if _value.is_using: # 使用中,无需处理 continue # 看是否要释放对象 _now = datetime.datetime.now() if self._current_size > self.minsize and (_now - _value.last_free_time).total_seconds() > self.realse_free_time: # 已经超过空闲时间了,释放连接,实际释放连接在后面再做 _is_realse = True self._current_size -= 1 del self._connection_pool[_key] if self._logger is not None: self._logger.log( logging.DEBUG, 'Connection Pool [%s] release free connection [%s], last free time [%s]' % ( self.name, _key, _value.last_free_time.strftime( '%Y-%m-%d %H:%M:%S') ) ) finally: self._access_lock.release() # 检查连接有效性,可能时间比较长,无需锁住对象 if not _is_realse and self.test_while_idle and (_now - _value.last_test_time).total_seconds() > self.test_idle_time: _test_result = self.test_connection(_value.connection) # 检查结果 if _test_result: # 通过检查,更新检查时间 _value.last_test_time = _now else: # 没有通过检查,需要再次锁定并进行释放 self._access_lock.acquire() try: if not _value.is_using: # 再次确认没有被外部获取,才进行删除 _is_realse = True self._current_size -= 1 del self._connection_pool[_key] if self._logger is not None: self._logger.log( logging.DEBUG, 'Connection Pool [%s] release invalid connection [%s]' % ( self.name, _key ) ) finally: self._access_lock.release() # 执行真正的关闭连接动作 if _is_realse: self._close_connection(_value.connection) else: # 没有释放,把对象放回空闲队列 self._free_pool.put(_key) # 进行下一次的循环 RunTool.sleep(self.daemon_sleep_time) # 运行到这里说明守护线程结束 self._daemon_running = False ############################# # 需要具体类实现的函数 ############################# @abstractmethod def _create_connection_self(self): """ 创建一个连接对象(具体类实现) @return {object} - 返回有效的连接对象 @throws {Exception} - 当创建失败或连接无效时应直接抛出异常 """ raise NotImplementedError @abstractmethod def _close_connection_self(self, connection): """ 关闭指定的连接对象(具体类实现) @param {object} connection - 要关闭的连接对象 @throws {Exception} - 当关闭失败时应直接抛出异常 """ raise NotImplementedError @abstractmethod def _test_connection_self(self, connection): """ 测试指定的连接对象是否有效(具体类实现) @param {object} connection - 要测试的连接对象 @throws {Exception} - 当测试失败时应抛出异常 """ raise NotImplementedError @abstractmethod def _reconnect_self(self, connection): """ 对指定对象重新进行连接(具体类实现) @param {object} connection - 要重新连接的对象 @return {object} - 返回有效的连接对象 @throws {Exception} - 当重连失败时应抛出异常 """ raise NotImplementedError
def __init__(self, connect_para, name='ConnectionPool', maxsize=100, minsize=0, realse_free_time=300, test_on_get=False, test_on_free=False, test_while_idle=True, test_idle_time=60, validation_query='', get_connection_timeout=0, logger=None, init_break_if_connect_error=True, daemon_sleep_time=1): """ 构造函数,创建连接池 @param {NullObj} connect_para - 连接参数,具体参数属性根据实现类指定 @param {string} name='ConnectionPool' - 连接池名称 @param {int} maxsize=100 - 最大连接数 @param {int} minsize=0 - 最小保持连接数 @param {number} realse_free_time=300 - 自动释放多长时间的空闲无操作连接(单位秒) @param {bool} test_on_get=False - 是否在获取连接前检查连接是否有效 @param {bool} test_on_free=False - 是否在归还连接时检查连接是否有效 @param {bool} test_while_idle=True - 是否检查空闲连接是否有效 @param {number} test_idle_time=60 - 自动检查空闲连接有效性的时间间隔(单位秒) @param {string} validation_query='' - 检查连接是否有效的查询语句(非数据库类的可以传入检查参数) @param {number} get_connection_timeout=0 - 获取连接的等待超时时间(单位秒),0代表不超时 @param {Logger} logger=None - 日志对象,服务过程中通过该函数写日志: 可以为标准的logging日志库对象,也可以为simple_log对象,但要求对象实现: 标准的info、debug、warning、error、critical五个日志方法 @param {bool} init_break_if_connect_error=True - 如果连接失败则初始化抛出异常 @param {number} daemon_sleep_time=1 - 守护进程的间隔刷新时间(单位秒) """ # 设置初始化参数 self.connect_para = connect_para self.name = name self.maxsize = maxsize self.minsize = minsize self.realse_free_time = realse_free_time self.test_on_get = test_on_get self.test_on_free = test_on_free self.test_while_idle = test_while_idle self.test_idle_time = test_idle_time self.validation_query = validation_query self.get_connection_timeout = get_connection_timeout self._logger = logger self.daemon_sleep_time = daemon_sleep_time # 应在__init__中初始化,否则会出现两个实例对象引用地址一样的问题 self._connection_pool = dict() self._free_pool = MemoryQueue(queue_type=EnumQueueType.LIFO, maxsize=0) self._access_lock = threading.Lock() # 按最小保持连接数创建连接 _i = 0 while _i < self.minsize: try: # 创建连接出现异常记录日志,并抛出异常 with ExceptionTool.ignored( expect=(), logger=self._logger, self_log_msg='Connection Pool [%s] Init Error ' % (self.name), force_log_level=logging.ERROR ): # 创建连接 _cid = self._create_connection() # 把连接加入到空闲池 self._free_pool.put(_cid) self._current_size += 1 except Exception as e: # 根据init_break_if_connect_error参数,如果为False则连接异常也继续处理 if init_break_if_connect_error: raise e _i += 1 # 创建守护线程,负责检查及释放空闲连接 _daemon_thread = threading.Thread( target=self.__start_daemon_thread_fun, args=(1,), name='DaemonThread-ConnectionPool[%s]' % (self.name) ) _daemon_thread.setDaemon(True) self._daemon_running = True _daemon_thread.start()
def test_fifo(self): """ 测试先进先出 """ print('测试先进先出 - 非水桶模式') queue = MemoryQueue(queue_type=EnumQueueType.FIFO, maxsize=3) queue.put(1) queue.put(2) queue.put(3) # 插入失败 - 抛出异常 try: print('队列已满,插入等待2秒后超时') queue.put(4, timeout=2) except Full: print('正常超时返回') except: self.assertTrue(False, '测试先进先出 - 非水桶模式 - 放入对象超时失败-出现其他异常') # 插入失败,直接返回 try: print('队列已满,插入不等待异常') queue.put(4, block=False) except Full: print('正常异常返回') except: self.assertTrue(False, '测试先进先出 - 非水桶模式 - 放入对象异常失败-出现其他异常') # 取数据 _get_str = ('%d%d%d' % (queue.get(), queue.get(), queue.get())) self.assertTrue( '123' == _get_str, '测试先进先出 - 非水桶模式 - 获取数据失败 %s' % _get_str ) # 空的情况取数据超时 try: print('队列已空,获取等待2秒后超时') queue.get(timeout=2) except Empty: print('正常超时返回') except: self.assertTrue(False, '测试先进先出 - 非水桶模式 - 获取对象超时失败-出现其他异常') # 获取失败,直接返回 try: print('队列已空,获取不等待异常') queue.get(block=False) except Empty: print('正常异常返回') except: self.assertTrue(False, '测试先进先出 - 非水桶模式 - 获取对象异常失败-出现其他异常') print('测试先进先出 - 水桶模式') queue = MemoryQueue(queue_type=EnumQueueType.FIFO, maxsize=3, bucket_mode=True) queue.put(1) queue.put(2) queue.put(3) queue.put(4) # 取数据 _get_str = ('%d%d%d' % (queue.get(), queue.get(), queue.get())) self.assertTrue( '234' == _get_str, '测试先进先出 - 水桶模式 - 获取数据失败 %s' % _get_str )
def test_priority(self): """ 测试优先级队列 """ print('测试优先级队列 - 非水桶模式') queue = MemoryQueue(queue_type=EnumQueueType.PRIORITY, maxsize=3) queue.put(1, priority=2) queue.put(2, priority=3) queue.put(3, priority=1) # 取数据 _get_str = ('%d%d%d' % (queue.get(), queue.get(), queue.get())) self.assertTrue( '213' == _get_str, '测试优先级队列 - 非水桶模式 - 获取数据失败 %s' % _get_str ) print('测试优先级队列 - 水桶模式') queue = MemoryQueue(queue_type=EnumQueueType.PRIORITY, maxsize=3, bucket_mode=True) queue.put(1, priority=2) queue.put(2, priority=3) queue.put(3, priority=1) queue.put(4, priority=1) # 取数据 _get_str = ('%d%d%d' % (queue.get(), queue.get(), queue.get())) self.assertTrue( '134' == _get_str, '测试优先级队列 - 水桶模式 - 获取数据失败 %s' % _get_str )
def test_lifo(self): """ 测试后进先出 """ print('测试后进先出 - 非水桶模式') queue = MemoryQueue(queue_type=EnumQueueType.LIFO, maxsize=3) queue.put(1) queue.put(2) queue.put(3) # 取数据 _get_str = ('%d%d%d' % (queue.get(), queue.get(), queue.get())) self.assertTrue( '321' == _get_str, '测试后进先出 - 非水桶模式 - 获取数据失败 %s' % _get_str ) print('测试后进先出 - 水桶模式') queue = MemoryQueue(queue_type=EnumQueueType.LIFO, maxsize=3, bucket_mode=True) queue.put(1) queue.put(2) queue.put(3) queue.put(4) # 取数据 _get_str = ('%d%d%d' % (queue.get(), queue.get(), queue.get())) self.assertTrue( '421' == _get_str, '测试后进先出 - 水桶模式 - 获取数据失败 %s' % _get_str )