python: LogHelper
# encoding: utf-8 # 版权所有 2026 ©涂聚文有限公司™ ® # 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 # 描述日志 # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2024.3.6 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2026/7/31 19:58 # User : geovindu # Product : PyCharm # Project : PyAlgorithms # File : LogHelper.py import os import sys import time import threading import queue import datetime import traceback import json import zipfile import random import re from enum import Enum from typing import Tuple, Optional, Dict, List, Any, Callable import atexit import platform import zoneinfo class LogLevel(Enum): 日志等级枚举与 C# 版本对齐 OFF 0 # 关闭输出 ERROR 1 INFO 2 DEBUG 3 # 类型别名 DesensitizeFunc Callable[[str, str, str], str] AlertCallbackFunc Callable[[str, str, Dict[str, Any]], None] class LogHelper: Python 异步日志工具类 新增特性业务模块分目录隔离存储 完整能力清单 1. 【新增】按业务模块分目录存储日志防止多业务日志混杂 2. 异步队列批量写入多线程安全、优雅退出 3. 文本 / JSON结构化日志动态切换异常堆栈独立字段 stack_trace 4. 控制台彩色输出开关自动按大小切割日志、备份自动zip压缩 5. 过期日志自动清理磁盘超限策略优先删zip再删log 6. 分级独立磁盘上限 全局总磁盘上限兜底 7. 全局/分级日志采样策略减轻高频日志IO压力 8. 日志脱敏回调函数支持携带模块名 9. 告警回调磁盘超限、队列拥堵事件通知 10.自定义时区、自定义时间格式化模板 日志文件生成样式 Logs/ ├─ default/ # 旧代码默认模块 │ ├─ info_20260731.log │ └─ debug_20260731.log ├─ user_service/ # 用户业务模块 │ └─ info_20260731.log ├─ order_service/ # 订单业务模块 │ └─ debug_20260731.log ├─ pay_service/ # 支付业务模块 │ └─ error_20260731.log └─ goods_service/ # 商品业务模块 └─ info_20260731.log # 【全局配置区 按需修改】 LOG_ROOT os.path.join(os.getcwd(), Logs) DEFAULT_MODULE default # 默认业务模块名称 KEEP_DAYS 7 # 日志保留天数 MAX_FILE_SIZE_MB 10 # 单个日志文件最大MB MAX_FILE_SIZE_BYTES MAX_FILE_SIZE_MB * 1024 * 1024 QUEUE_MAXSIZE 10000 QUEUE_ALERT_THRESHOLD 7000 BATCH_WRITE_COUNT 10 ENABLE_CONSOLE_OUTPUT True ENABLE_JSON_FORMAT False COMPRESS_BAK_LOG True # 磁盘容量限制 MB MAX_DISK_TOTAL_MB 500 LEVEL_DISK_LIMIT { debug: 150, info: 250, error: 100 } # 采样配置 0~1.0 GLOBAL_SAMPLING_RATE 1.0 LEVEL_SAMPLING_RATE { debug: 1.0, info: 1.0, error: 1.0 } DISK_CHECK_INTERVAL_SEC 60 TIME_ZONE_NAME Asia/Shanghai TIME_FORMAT_TEMPLATE %Y-%m-%d %H:%M:%S _log_level LogLevel.DEBUG # 外部回调注册 _desensitize_callback: Optional[DesensitizeFunc] None _alert_callback: Optional[AlertCallbackFunc] None # 内部变量 _log_queue: queue.Queue queue.Queue(QUEUE_MAXSIZE) _stop_event threading.Event() _writer_thread: Optional[threading.Thread] None _last_clean_time: datetime.datetime _last_disk_check_time 0.0 _init_finished False _file_operate_lock threading.Lock() _pid os.getpid() _tz_info: Optional[zoneinfo.ZoneInfo] None # 控制台颜色 _COLOR_MAP { DEBUG: \033[34m, INFO: \033[32m, ERROR: \033[31m, RESET: \033[0m } if platform.system() Windows: try: import ctypes kernel32 ctypes.windll.kernel32 kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) except Exception: for k in _COLOR_MAP: _COLOR_MAP[k] classmethod def _safe_module_name(cls, module: str) - str: 安全过滤模块名称防止路径穿越、非法字符 :param module: :return: if not isinstance(module, str) or module.strip() : return cls.DEFAULT_MODULE # 只允许字母数字下划线横杠 safe_str re.sub(r[^\w\-], _, module.strip()) return safe_str classmethod def get_module_log_dir(cls, module: str) - str: 获取指定业务模块日志根目录 :param module: :return: mod_name cls._safe_module_name(module) return os.path.join(cls.LOG_ROOT, mod_name) classmethod def _init_timezone(cls): :return: try: cls._tz_info zoneinfo.ZoneInfo(cls.TIME_ZONE_NAME) except Exception: cls._tz_info None classmethod def get_now_datetime(cls) - datetime.datetime: :return: if cls._tz_info: return datetime.datetime.now(tzcls._tz_info) return datetime.datetime.now() # 回调注册API classmethod def register_desensitize(cls, func: DesensitizeFunc): 脱敏回调签名func(level:str, module:str, msg:str) - str cls._desensitize_callback func classmethod def register_alert_callback(cls, func: AlertCallbackFunc): :param func: :return: cls._alert_callback func # 动态配置API classmethod def set_log_level(cls, level: LogLevel): :param level: :return: cls._log_level level classmethod def switch_json_format(cls, enable: bool): :param enable: :return: cls.ENABLE_JSON_FORMAT enable classmethod def switch_console(cls, enable: bool): cls.ENABLE_CONSOLE_OUTPUT enable classmethod def set_timezone(cls, tz_name: str): :param tz_name: :return: cls.TIME_ZONE_NAME tz_name cls._init_timezone() classmethod def set_time_format(cls, fmt_str: str): :param fmt_str: :return: cls.TIME_FORMAT_TEMPLATE fmt_str classmethod def set_sampling_rate(cls, level: str, rate: float): :param level: :param rate: :return: rate max(0.0, min(1.0, rate)) cls.LEVEL_SAMPLING_RATE[level.lower()] rate # 采样判断 classmethod def _need_sample(cls, level: str) - bool: :param level: :return: lv level.lower() lv_rate cls.LEVEL_SAMPLING_RATE.get(lv, 1.0) final_rate cls.GLOBAL_SAMPLING_RATE * lv_rate if final_rate 1.0: return True return random.random() final_rate # 磁盘空间管理适配模块目录 classmethod def _get_dir_total_size_mb(cls, folder: str, filter_prefix: str None) - float: :param folder: :param filter_prefix: :return: total_bytes 0 if not os.path.exists(folder): return 0.0 for entry in os.scandir(folder): if entry.is_dir(): # 递归遍历模块子目录 total_bytes cls._get_dir_total_size_mb(entry.path, filter_prefix) continue if not entry.is_file(): continue if not (entry.name.endswith(.log) or entry.name.endswith(.zip)): continue if filter_prefix is not None and not entry.name.startswith(f{filter_prefix}_): continue total_bytes entry.stat().st_size return total_bytes / 1024 / 1024 classmethod def _get_sorted_log_files(cls, folder: str, filter_prefix: str None): :param folder: :param filter_prefix: :return: file_list [] if not os.path.exists(folder): return file_list for entry in os.scandir(folder): if entry.is_dir(): file_list.extend(cls._get_sorted_log_files(entry.path, filter_prefix)) continue if not entry.is_file(): continue if not (entry.name.endswith(.log) or entry.name.endswith(.zip)): continue if filter_prefix is not None and not entry.name.startswith(f{filter_prefix}_): continue file_list.append((entry.stat().st_mtime, entry.path)) file_list.sort(keylambda x: x[0]) return [item[1] for item in file_list] classmethod def _trigger_alert(cls, event_type: str, message: str, ext: Dict[str, Any] None): :param event_type: :param message: :param ext: :return: if cls._alert_callback is None: return try: ext_info ext if ext is not None else {} cls._alert_callback(event_type, message, ext_info) except Exception: pass classmethod def _try_free_disk_space(cls, level: str None) - bool: :param level: :return: while True: if level is not None: usage_mb cls._get_dir_total_size_mb(cls.LOG_ROOT, filter_prefixlevel) limit_mb cls.LEVEL_DISK_LIMIT.get(level, cls.MAX_DISK_TOTAL_MB) if usage_mb limit_mb: return True else: usage_mb cls._get_dir_total_size_mb(cls.LOG_ROOT) if usage_mb cls.MAX_DISK_TOTAL_MB: return True all_files cls._get_sorted_log_files(cls.LOG_ROOT, filter_prefixlevel) if not all_files: return False deleted False # 优先删除zip for fp in all_files: if fp.endswith(.zip): try: os.remove(fp) print(f[LogHelper CLEAN] 磁盘超限删除老旧压缩包{os.path.basename(fp)}, filesys.stderr) deleted True break except Exception: continue if deleted: continue # 删除log for fp in all_files: if fp.endswith(.log): try: os.remove(fp) print(f[LogHelper CLEAN] 磁盘超限删除老旧日志{os.path.basename(fp)}, filesys.stderr) deleted True break except Exception: continue if not deleted: return False classmethod def _check_disk_limit(cls, level: str) - bool: :param level: :return: now_ts time.time() if now_ts - cls._last_disk_check_time cls.DISK_CHECK_INTERVAL_SEC: return False cls._last_disk_check_time now_ts lv level.lower() lv_usage cls._get_dir_total_size_mb(cls.LOG_ROOT, lv) lv_limit cls.LEVEL_DISK_LIMIT.get(lv, cls.MAX_DISK_TOTAL_MB) total_usage cls._get_dir_total_size_mb(cls.LOG_ROOT) over_flag False if lv_usage lv_limit: cls._trigger_alert( DISK_OVER_LIMIT, f日志【{level}】分级磁盘占用超限({lv_usage:.2f}MB/{lv_limit}MB)开始清理, {level: level, usage_mb: lv_usage, limit_mb: lv_limit, total_usage: total_usage} ) success cls._try_free_disk_space(lv) if not success: over_flag True elif total_usage cls.MAX_DISK_TOTAL_MB: cls._trigger_alert( DISK_OVER_LIMIT, f日志总磁盘占用超限({total_usage:.2f}MB/{cls.MAX_DISK_TOTAL_MB}MB)开始清理, {usage_mb: total_usage, limit_mb: cls.MAX_DISK_TOTAL_MB} ) success cls._try_free_disk_space() if not success: over_flag True if over_flag: print(f[LogHelper FATAL] 清理后磁盘依旧超限暂停持久化写入【{level}】日志, filesys.stderr) return over_flag classmethod def _init(cls) - None: :return: if cls._init_finished: return os.makedirs(cls.LOG_ROOT, exist_okTrue) cls._init_timezone() cls._last_clean_time cls.get_now_datetime() cls._stop_event.clear() cls._writer_thread threading.Thread( targetcls._write_log_loop, nameLogHelper-Writer, daemonTrue ) cls._writer_thread.start() atexit.register(cls._shutdown) cls._init_finished True classmethod def _get_caller_info(cls) - Tuple[str, str, str, int]: :return: try: frame sys._getframe(4) while frame: if frame.f_code.co_filename ! __file__: class_name 未知类 if self in frame.f_locals: class_name frame.f_locals[self].__class__.__name__ elif cls in frame.f_locals: class_name frame.f_locals[cls].__name__ return ( os.path.basename(frame.f_code.co_filename), class_name, frame.f_code.co_name, frame.f_lineno ) frame frame.f_back except Exception: pass return (未知文件, 未知类, 未知方法, 0) classmethod def _build_log_data(cls, level: str, module: str, msg: str, stack_trace: str ) - str | Dict[str, Any]: :param level: :param module: :param msg: :param stack_trace: :return: mod_name cls._safe_module_name(module) # 脱敏回调携带模块名 if cls._desensitize_callback is not None: try: msg cls._desensitize_callback(level, mod_name, msg) except Exception: pass filename, class_name, method_name, line_no cls._get_caller_info() now cls.get_now_datetime() log_time_str now.strftime(cls.TIME_FORMAT_TEMPLATE) timestamp now.timestamp() thread_name threading.current_thread().name if cls.ENABLE_JSON_FORMAT: data { time: log_time_str, timestamp: timestamp, level: level, module: mod_name, pid: cls._pid, thread: thread_name, file: filename, class: class_name, function: method_name, line: line_no, message: msg, stack_trace: stack_trace if stack_trace else None } return data else: text ( f[{log_time_str}] [{level}] [MODULE:{mod_name}] [PID:{cls._pid}] [THREAD:{thread_name}] f[{class_name}.{method_name}·{line_no}行·{filename}] {msg} ) if stack_trace: text f\n{stack_trace} text \n return text classmethod def _enqueue_log(cls, level: str, module: str, msg: str, stack_trace: str ) - None: :param level: :param module: :param msg: :param stack_trace: :return: if not cls._need_sample(level): return try: log_item cls._build_log_data(level, module, msg, stack_trace) # 控制台输出 if cls.ENABLE_CONSOLE_OUTPUT: if isinstance(log_item, dict): console_str json.dumps(log_item, ensure_asciiFalse) else: console_str log_item.rstrip(\n) color cls._COLOR_MAP.get(level, ) reset cls._COLOR_MAP[RESET] print(f{color}{console_str}{reset}) queue_size cls._log_queue.qsize() if queue_size cls.QUEUE_ALERT_THRESHOLD: cls._trigger_alert( QUEUE_BLOCKED, f日志队列拥堵当前队列长度:{queue_size}, {queue_size: queue_size, max_queue: cls.QUEUE_MAXSIZE} ) mod_safe cls._safe_module_name(module) cls._log_queue.put_nowait((level.lower(), mod_safe, log_item)) except queue.Full: print([LogHelper WARN] 日志队列已满丢弃日志, filesys.stderr) except Exception as e: print(f[LogHelper ERROR] 组装日志异常:{e}, filesys.stderr) classmethod def _get_log_path(cls, level: str, module: str) - str: :param level: :param module: :return: mod_dir cls.get_module_log_dir(module) os.makedirs(mod_dir, exist_okTrue) date_str cls.get_now_datetime().strftime(%Y%m%d) return os.path.join(mod_dir, f{level}_{date_str}.log) classmethod def _compress_file(cls, src_file: str): :param src_file: :return: if not os.path.exists(src_file) or not cls.COMPRESS_BAK_LOG: return try: zip_path src_file.replace(.log, .zip) with zipfile.ZipFile(zip_path, w, compressionzipfile.ZIP_DEFLATED) as zf: zf.write(src_file, arcnameos.path.basename(src_file)) os.remove(src_file) except Exception as e: print(f[LogHelper] 日志压缩失败:{src_file}, err:{e}, filesys.stderr) classmethod def _check_and_split(cls, log_path: str) - None: :param log_path: :return: with cls._file_operate_lock: if not os.path.exists(log_path): return try: if os.path.getsize(log_path) cls.MAX_FILE_SIZE_BYTES: base os.path.splitext(log_path)[0] bak_path f{base}_{time.strftime(%H%M%S)}.log os.rename(log_path, bak_path) threading.Thread(targetcls._compress_file, args(bak_path,), daemonTrue).start() except Exception as e: print(f[LogHelper] 文件切割异常:{e}, filesys.stderr) classmethod def _clean_old_logs(cls) - None: :return: now cls.get_now_datetime() expire_time now - datetime.timedelta(dayscls.KEEP_DAYS) with cls._file_operate_lock: if not os.path.exists(cls.LOG_ROOT): return for root, _, files in os.walk(cls.LOG_ROOT): for filename in files: if not (filename.endswith(.log) or filename.endswith(.zip)): continue file_path os.path.join(root, filename) try: mtime datetime.datetime.fromtimestamp(os.path.getmtime(file_path), tzcls._tz_info) if mtime expire_time: os.remove(file_path) except Exception as e: print(f[LogHelper] 清理过期文件失败 {filename}:{e}, filesys.stderr) classmethod def _write_log_loop(cls) - None: :return: # buffer key: (level, module) buffer: Dict[Tuple[str, str], List[Any]] {} while not cls._stop_event.is_set(): try: level, module, log_item cls._log_queue.get(timeout0.8) key (level, module) buffer.setdefault(key, []).append(log_item) if len(buffer[key]) cls.BATCH_WRITE_COUNT: cls._flush_buffer(buffer, key) except queue.Empty: if buffer: cls._flush_buffer(buffer) continue except Exception as e: print(f[LogHelper] 写入循环异常: {e}, filesys.stderr) if buffer: cls._flush_buffer(buffer) classmethod def _flush_buffer(cls, buffer: Dict[Tuple[str, str], List[Any]], target_key: Tuple[str, str] None): :param buffer: :param target_key: :return: target_keys [target_key] if target_key else list(buffer.keys()) for key in target_keys: level, module key msg_list buffer.get(key) if not msg_list: continue try: disk_over cls._check_disk_limit(level) if disk_over: buffer[key].clear() continue log_path cls._get_log_path(level, module) cls._check_and_split(log_path) lines [] for item in msg_list: if isinstance(item, dict): lines.append(json.dumps(item, ensure_asciiFalse) \n) else: lines.append(item) with open(log_path, a, encodingutf-8) as f: f.writelines(lines) f.flush() buffer[key].clear() except Exception as e: print(f[LogHelper] 文件写入失败 level:{level}, module:{module}, err:{e}, filesys.stderr) now cls.get_now_datetime() if now.date() ! cls._last_clean_time.date(): cls._clean_old_logs() cls._last_clean_time now # 对外API【兼容旧代码 新增模块版本】 # 原有接口默认模块 default历史代码无需改动 classmethod def debug(cls, msg: str): :param msg: :return: if cls._log_level.value LogLevel.DEBUG.value: cls._enqueue_log(DEBUG, cls.DEFAULT_MODULE, msg) classmethod def info(cls, msg: str): :param msg: :return: if cls._log_level.value LogLevel.INFO.value: cls._enqueue_log(INFO, cls.DEFAULT_MODULE, msg) classmethod def error(cls, msg: str, exc: Optional[Exception] None): :param msg: :param exc: :return: if cls._log_level.value LogLevel.ERROR.value: return stack_str if exc: stack_str .join(traceback.format_exception(type(exc), exc, exc.__traceback__)) cls._enqueue_log(ERROR, cls.DEFAULT_MODULE, msg, stack_str) # 新增支持指定业务模块的日志接口 classmethod def debug_mod(cls, module: str, msg: str): :param module: :param msg: :return: if cls._log_level.value LogLevel.DEBUG.value: cls._enqueue_log(DEBUG, module, msg) classmethod def info_mod(cls, module: str, msg: str): :param module: :param msg: :return: if cls._log_level.value LogLevel.INFO.value: cls._enqueue_log(INFO, module, msg) classmethod def error_mod(cls, module: str, msg: str, exc: Optional[Exception] None): :param module: :param msg: :param exc: :return: if cls._log_level.value LogLevel.ERROR.value: return stack_str if exc: stack_str .join(traceback.format_exception(type(exc), exc, exc.__traceback__)) cls._enqueue_log(ERROR, module, msg, stack_str) classmethod def _shutdown(cls): :return: cls._stop_event.set() try: cls._log_queue.join() except Exception: pass if cls._writer_thread: cls._writer_thread.join(timeout3.0) # 模块导入自动初始化 LogHelper._init()调用# encoding: utf-8 # 版权所有 2026 ©涂聚文有限公司™ ® # 许可信息查看言語成了邀功盡責的功臣還需要行爲每日來值班嗎 # 描述日志 # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2024.3.6 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2026/7/31 14:16 # User : geovindu # Product : PyCharm # Project : ictsimple # File : logtest.py from loghelper import LogHelper,LogLevel import time import os if __name__ __main__: # 时区、时间格式动态修改示例 # LogHelper.set_timezone(UTC) # LogHelper.set_time_format(%Y-%m-%d %H:%M:%S.%f) # #TIME_ZONE_NAME Asia/Shanghai #TIME_FORMAT_TEMPLATE %Y-%m-%d %H:%M:%S # 1. 脱敏回调新增参数 module def demo_desensitize(level: str, module: str, msg: str) - str: import re msg re.sub(r1[3-9]\d{9}, lambda m: m.group()[:3] **** m.group()[7:], msg) return msg LogHelper.register_desensitize(demo_desensitize) # 2. 告警回调 def demo_alert(event_type, msg, ext): print(f\n【ALERT】{event_type} | {msg} | {ext}\n) LogHelper.register_alert_callback(demo_alert) # 3. 原有调用方式默认模块 default LogHelper.info(【默认模块】系统启动手机号13800138000) # 4. 【核心新增】按业务模块输出日志 LogHelper.info_mod(user_service, 用户模块注册成功 13900139000) LogHelper.debug_mod(order_service, 订单模块创建订单请求) try: 1 / 0 except Exception as e: LogHelper.error_mod(pay_service, 支付模块异常, e) # 切换JSON格式 LogHelper.switch_json_format(True) LogHelper.info_mod(goods_service, 商品模块查询库存) input(回车退出...)

相关新闻

GPT-5.5 516令牌断崖现象:成因、影响与工程应对策略

GPT-5.5 516令牌断崖现象:成因、影响与工程应对策略

1. 当“聪明”的模型突然变“笨”:GPT-5.5的516令牌断崖现象最近,不少深度使用GPT-5.5模型进行代码生成、复杂逻辑推理或长文本创作的朋友,可能都遇到了一个让人挠头又有点哭笑不得的问题:模型在思考到某个特定长度时,…

2026/8/1 3:51:13 阅读更多 →
LeetCode 17. 电话号码的字母组合

LeetCode 17. 电话号码的字母组合

题目描述给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按任意顺序返回。数字到字母的映射与电话按键相同:2 -> abc 3 -> def 4 -> ghi 5 -> jkl 6 -> mno 7 -> pqrs 8 -> tuv 9 -> wxyz注意&#xff1…

2026/8/1 3:51:13 阅读更多 →
吉他扫弦节奏型训练方法论

吉他扫弦节奏型训练方法论

本文以「问题导向 可操作步骤 练习计划表」结构,拆解吉他右手扫弦节奏型训练。适用于能和弦转换、但扫弦断拍的学习者。1. 问题归因(4 类)1.1 以臂代腕。 手腕未放松甩动,整臂抡动难控。1.2 未稳叠和弦。 右手未固化即加左手&am…

2026/8/1 3:51:13 阅读更多 →

最新新闻

【Matlab】等离子体物理粒子模拟实现

【Matlab】等离子体物理粒子模拟实现

【Matlab】等离子体物理粒子模拟实现 一、引言 等离子体是由自由电子、带电离子与中性粒子组成的电离气体体系,被称为物质的第四种形态,广泛存在于宇宙空间、大气电离层、核聚变装置、等离子体刻蚀设备、微波放电装置与航空推进系统中。相较于固液气三种常规物质形态,等离…

2026/8/1 4:31:30 阅读更多 →
智能锡膏柜居然还有标准?新手怎么选?

智能锡膏柜居然还有标准?新手怎么选?

智能锡膏柜到底有没有标准?新手怎么选不出错?“智能锡膏柜到底有没有标准?”——这是我在后台收到最多的问题,没有之一。很多采购、工艺主管和SMT老板面对市场上功能五花八门、价格从几万到十几万不等的“智能柜”,往往…

2026/8/1 4:31:30 阅读更多 →
React富文本编辑器核心架构与实现解析

React富文本编辑器核心架构与实现解析

1. 富文本编辑器核心架构解析富文本编辑器的本质是在浏览器中模拟桌面文字处理软件的交互体验。与普通textarea不同,它需要处理复杂的文档结构、样式嵌套和用户操作记录。在React生态中实现这一功能,我们需要先理解几个核心概念:可编辑节点&a…

2026/8/1 4:31:30 阅读更多 →
TSB自定义技能系统:组件化开发与手机端性能优化实战

TSB自定义技能系统:组件化开发与手机端性能优化实战

最近在游戏开发圈里,TSB(Technical Skill Builder)框架的自定义技能系统突然火了起来。很多开发者发现,过去需要复杂代码才能实现的"空间斩"和"连续斩击"这类高级技能效果,现在通过TSB的可视化配置…

2026/8/1 4:31:30 阅读更多 →
C++自定义类型哈希实现:从原理到实战避坑指南

C++自定义类型哈希实现:从原理到实战避坑指南

1. 从一次“找不到对象”的编译错误说起那天下午&#xff0c;我正在调试一个处理海量用户数据的模块&#xff0c;核心数据结构是一个std::unordered_map<User, UserProfile>。User是我自定义的一个类&#xff0c;包含了用户ID、姓名哈希和一些状态标志。代码逻辑看起来天…

2026/8/1 4:31:30 阅读更多 →
VH6501总线干扰神器实战:从硬件原理到CAPL脚本的汽车ECU压力测试指南

VH6501总线干扰神器实战:从硬件原理到CAPL脚本的汽车ECU压力测试指南

1. 项目概述&#xff1a;从“干扰”到“测试”的认知升级提到“总线干扰神器”&#xff0c;很多刚接触汽车电子测试的朋友可能会眼睛一亮&#xff0c;觉得这玩意儿是不是能像电影里的黑客工具一样&#xff0c;随便一按就让别人的CAN网络瘫痪&#xff1f;我最初拿到VH6501时也闪…

2026/8/1 4:30:29 阅读更多 →

日新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/1 0:00:48 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/1 0:00:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/1 0:00:48 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档&#xff0c;可以直接使用&#xff01;系统支持图片、视频、摄像头等多种方式检测裂缝&#xff0c;功能强大实用。 1数据集6000张 8各类别

2026/7/31 1:03:03 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像&#xff01; pubg绝地求生目标检测数据集 1分类&#xff1a;e_body&#xff0c;14905个标签&#xff0c;txt格式 共计14244张图&#xff0c;99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别&#xff1a; allies enemy tag图片总量&#xff1a;7247张训练集&#xff1a;5139张验证集&#xff1a;1425张测试集&#xff1a;683张标注状态&#xff1a;全部已标注&#xff0c;即拿即用数据格式&#xff1a;支持YOLO格式及其他格式&#…

2026/7/31 4:19:39 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/1 0:00:48 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/1 0:00:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/1 0:00:48 阅读更多 →