异常执行顺序(exception specification)

之前都没有好好练习过异常,也没有深入了解过,最近在看Thinking In C++中,它的第一章就讲述了大量的异常代码,本以为很简单,然而在机器上编译调试了一番,才发现并不是那么一回事。在执行下面的异常程序中,发现很有些特色(可能老手早就熟悉了),记录下来, 以便将来查看!程序源代码为:

//: C01: Unexpcected.cpp

// Exception specifications & unexcepted(),
//{-msc} (doesn't terminate properly)

#include 
<exception>
#include 
<iostream>

using namespace std;

class Up{};
class Fit{};
void g();

void f(int i) throw(Up,Fit)
{
    
switch(i)
    
{
    
case 1throw Up();
    
case 2throw Fit();
    }

    g();
}



// void g() {} //version 1
void g()
{
    
throw 32;
}


void my_unexpected()
{
    cout
<<" unexpected exception thrown"<<endl;
    exit(
0);
}


int main()
{
    set_unexpected(my_unexpected);  
// Ignores return value
    forint i=1; i<=3; i++)
        
try
    
{
        f(i);
    }

    
catch(Up)
    
{
        cout
<<"Up caught"<<endl;    
    }

    
catch(Fit)
    
{
        cout
<<"Fit caught"<<endl;
    }

    
return 0;
}
 ///:~

 

整个程序结构非常简单,set_unexpected函数是exception头文件中提供的标准函数,用来设置抛出的异常没有列在异常规格说明(exception specification)的异常集中调用的unexpected函数(默认)

f 函数申明了异常规格说明集合,但调用了版本2的g 函数,而该函数抛出的异常却不在f 函数的异常规格说明集合中,因此将默认调用unexpected函数,此处将调用my_unexpected函数。

在VC中调试运行该函数,抛出出错对话框:

之后调试该程序,才惊奇的发现该程序运行顺序为
    首先执行for语句,然后执行try块中的f 函数调用,之后抛出Up异常,跳转到catch(Up)语句处执行,输出Up caught后,跳转到return 0语句,之后再执行for语句,再一次循环,抛出Fit异常,return 0之后再运行for语句,抛出Debug Error 对话框!

   原来异常程序的执行是如此的巧妙!

正如文中所说:把try块嵌入在for,while,do或if块中,并且触发异常来试图解决问题;然后重新测试try块中的代码!也就是说,即使其中一个执行过程抛出了异常,for,while,do或if等都能够继续执行下去,只针对其中一个过程产生影响,对全局影响并不是很大。

该程序在cygwin中可以被正确编译运行!说明了VC对标准C++的支持不是很好!

# E:\AI_System\environment\hardware_manager.py import platform import psutil import json import time import subprocess import logging from pathlib import Path from datetime import datetime from .db_manager import get_environment_db logger = logging.getLogger('HardwareManager') class HardwareManager: """ 硬件环境管理器 - 代表AI的家具环境、集成数据库支持 负责管理硬件配置、请求新硬件、监控硬件状态 """ def __init__(self, config_path: Path = None): """ 初始化硬件管理器 :param config_path: 硬件配置文件的路径 """ # 获取数据库实例 self.db = get_environment_db() # 加载硬件目录当前配置 self.available_hardware = self.load_hardware_catalog() self.current_setup = self.load_current_config(config_path) # 记录硬件启动事件 self.db.log_event( "system_start", f"硬件管理器启动: {platform.node()}", severity=1 ) # 保存当前配置到数据库 self.save_current_setup_to_db() # 设置最后更新时间 self.last_update = time.time() logger.info("✅ 硬件管理器初始化完成") def load_hardware_catalog(self) -> dict: """加载可用硬件目录(家具清单)""" return { "cpu": ["Intel i9-13900K", "AMD Ryzen 9 7950X", "Apple M2 Max", "Qualcomm Snapdragon X Elite"], "gpu": ["NVIDIA RTX 4090", "AMD Radeon RX 7900 XTX", "Apple M2 GPU", "NVIDIA RTX 6000 Ada"], "memory": [16, 32, 64, 128, 256], # GB "storage": ["1TB SSD", "2TB SSD", "4TB SSD", "8TB SSD", "16TB HDD", "32TB NAS"], "peripherals": [ "4K Camera", "3D Scanner", "High-Fidelity Microphone", "VR Headset", "Haptic Gloves", "Eye Tracking Device" ], "network": ["10Gb Ethernet", "WiFi 6E", "5G Modem", "Satellite Link"] } def load_current_config(self, config_path: Path = None) -> dict: """ 加载当前硬件配置 :param config_path: 配置文件路径,如果为None则自动检测 """ config_data = {} # 1. 尝试从配置文件加载 if config_path and config_path.exists(): try: with open(config_path, 'r', encoding='utf-8') as f: config_data = json.load(f) logger.info(f"从配置文件加载硬件配置: {config_path}") except Exception as e: logger.error(f"配置文件加载失败: {str(e)}") # 2. 自动检测缺失的硬件信息 auto_detected = { "cpu": platform.processor(), "gpu": self.detect_gpu(), "memory": round(psutil.virtual_memory().total / (1024 ** 3), 1), "storage": round(psutil.disk_usage('/').total / (1024 ** 3), 1), "os": f"{platform.system()} {platform.release()}", "architecture": platform.architecture()[0], "machine": platform.machine() } # 3. 尝试从数据库加载最新配置 try: # 获取最近安装的硬件配置 history = self.db.get_hardware_history(limit=10) db_config = {} # 只取已安装的硬件配置 for item in history: if item['status'] == 'installed': # 使用最新的安装记录 if item['hardware_type'] not in db_config: db_config[item['hardware_type']] = item['specification'] # 合并到配置数据 config_data = {**config_data, **db_config} logger.info("从数据库加载硬件配置") except Exception as e: logger.warning(f"数据库配置加载失败: {str(e)}") # 合并配置(优先级: 数据库 > 配置文件 > 自动检测) return {**auto_detected, **config_data} def detect_gpu(self) -> str: """自动检测GPU型号""" try: # Windows系统检测 if platform.system() == "Windows": try: import wmi w = wmi.WMI() for gpu in w.Win32_VideoController(): return gpu.Name except ImportError: # 回退方法 result = subprocess.run( ['powershell', '-Command', 'Get-WmiObject Win32_VideoController | Select-Object -ExpandProperty Name'], stdout=subprocess.PIPE, text=True, check=True ) return result.stdout.strip().split('\n')[0] # Linux系统检测 elif platform.system() == "Linux": try: result = subprocess.run( ['lspci', '-vnn'], stdout=subprocess.PIPE, text=True, check=True ) for line in result.stdout.split('\n'): if 'VGA' in line or '3D' in line: parts = line.split(': ') if len(parts) > 1: return parts[1].split(' (')[0] except FileNotFoundError: # 尝试替代方法 with open('/proc/driver/nvidia/gpus/0000:01:00.0/information', 'r') as f: for line in f: if 'Model:' in line: return line.split(': ')[1].strip() # macOS检测 elif platform.system() == "Darwin": result = subprocess.run( ['system_profiler', 'SPDisplaysDataType'], stdout=subprocess.PIPE, text=True, check=True ) for line in result.stdout.split('\n'): if 'Chipset Model' in line: return line.split(': ')[1].strip() elif 'Graphics/Displays' in line: return line.split(': ')[1].strip() except Exception as e: logger.warning(f"GPU检测失败: {str(e)}") return "Unknown GPU" def request_hardware(self, hardware_type: str, specification: str) -> tuple: """ 请求新硬件(家具) :param hardware_type: 硬件类型 (cpu, gpu, memory等) :param specification: 硬件规格 :return: (是否成功, 消息) """ if hardware_type not in self.available_hardware: return False, f"不支持硬件类型: {hardware_type}" if specification not in self.available_hardware[hardware_type]: return False, f"不支持的规格: {specification}" # 在实际系统中,这里会生成硬件购买请求 self.current_setup[hardware_type] = specification self.last_update = time.time() # 记录到数据库 self.db.log_hardware_request(hardware_type, specification, "AI System") # 记录事件 self.db.log_event( "hardware_request", f"请求新硬件: {hardware_type} - {specification}", severity=2 ) return True, f"已请求 {hardware_type}: {specification}。请管理员完成安装。" def confirm_hardware_installation(self, hardware_type: str, specification: str) -> tuple: """ 确认硬件安装完成 :param hardware_type: 硬件类型 :param specification: 硬件规格 :return: (是否成功, 消息) """ # 更新当前设置 self.current_setup[hardware_type] = specification self.last_update = time.time() # 更新数据库状态 self.db.log_hardware_installation(hardware_type, specification) # 记录事件 self.db.log_event( "hardware_install", f"硬件安装完成: {hardware_type} - {specification}", severity=3 ) return True, f"硬件 {hardware_type}: {specification} 安装完成" def get_current_setup(self) -> dict: """获取当前硬件配置""" return self.current_setup def get_performance_metrics(self) -> dict: """获取硬件性能指标""" # 获取性能数据 metrics = { "timestamp": datetime.now().isoformat(), "cpu_usage": psutil.cpu_percent(interval=1), "memory_usage": psutil.virtual_memory().percent, "disk_usage": psutil.disk_usage('/').percent, "cpu_temp": self.get_cpu_temperature(), "gpu_temp": self.get_gpu_temperature(), "network_io": self.get_network_io(), "last_updated": time.time() } # 保存到数据库 self.db.save_environment_state(metrics) return metrics def get_cpu_temperature(self) -> float: """获取CPU温度""" try: if hasattr(psutil, "sensors_temperatures"): temps = psutil.sensors_temperatures() if 'coretemp' in temps: return max([t.current for t in temps['coretemp'] if 'Core' in t.label]) return 40.0 # 默认值 except: return 40.0 def get_gpu_temperature(self) -> float: """获取GPU温度""" try: # Windows系统检测 if platform.system() == "Windows": import wmi w = wmi.WMI(namespace="root\\WMI") gpu_data = w.MSAcpi_ThermalZoneTemperature()[0] return gpu_data.CurrentTemperature / 10.0 - 273.15 # Linux系统检测 elif platform.system() == "Linux": with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f: return int(f.read().strip()) / 1000.0 return 50.0 # 默认值 except: return 50.0 def get_network_io(self) -> dict: """获取网络IO数据""" net_io = psutil.net_io_counters() return { "bytes_sent": net_io.bytes_sent, "bytes_recv": net_io.bytes_recv, "packets_sent": net_io.packets_sent, "packets_recv": net_io.packets_recv } def save_config(self, config_path: Path) -> bool: """保存当前配置到文件""" try: with open(config_path, 'w', encoding='utf-8') as f: json.dump(self.current_setup, f, indent=2) return True except Exception as e: logger.error(f"配置保存失败: {str(e)}") return False def save_current_setup_to_db(self) -> bool: """保存当前硬件配置到数据库""" try: for hw_type, spec in self.current_setup.items(): # 只记录已知硬件类型 if hw_type in self.available_hardware: # 检查是否已存在相同配置 self.db.log_hardware_request(hw_type, str(spec), "System Initialization") self.db.log_hardware_installation(hw_type, str(spec)) return True except Exception as e: logger.error(f"保存配置到数据库失败: {str(e)}") return False def get_hardware_history(self, limit: int = 10) -> list: """从数据库获取硬件变更历史""" try: return self.db.get_hardware_history(limit) except Exception as e: logger.error(f"获取硬件历史失败: {str(e)}") return [] def simulate_hardware_upgrade(self, hardware_type: str, new_spec: str) -> tuple: """ 模拟硬件升级(用于测试) :param hardware_type: 硬件类型 :param new_spec: 新规格 :return: (是否成功, 消息) """ if hardware_type not in self.current_setup: return False, f"当前配置中没有 {hardware_type}" # 记录升级请求 self.db.log_hardware_request(hardware_type, new_spec, "Simulation") # 模拟安装过程 time.sleep(1) # 模拟安装延迟 # 确认安装 self.confirm_hardware_installation(hardware_type, new_spec) # 更新当前配置 self.current_setup[hardware_type] = new_spec return True, f"成功模拟 {hardware_type} 升级到 {new_spec}" # 工厂函数,便于在其他模块中创建实例 def create_hardware_manager(config_path: str = None) -> HardwareManager: """ 创建硬件管理器实例 :param config_path: 可选的自定义配置文件路径 """ path = Path(config_path) if config_path else None return HardwareManager(path) 辛苦啦
最新发布
08-10
<think>我们注意到在`HardwareManager`类中,使用了`from .db_manager import get_environment_db`来导入数据库管理模块。但是,在大型项目中,模块之间的循环导入可能会导致问题。因此,我们需要确保模块之间的依赖关系清晰,并且避免循环导入。 另外,在`HardwareManager`的初始化中,我们调用了`self.db.log_event`,如果`db_manager`模块还没有完全初始化,可能会导致错误。因此,我们需要确保数据库连接是可靠的。 此外,我们注意到`get_environment_db`函数返回一个数据库实例。我们需要确保这个实例是单例的,并且在整个应用中只有一个实例。 考虑到项目结构,我们可能需要在`environment`模块中有一个`__init__.py`文件,来管理模块的导出初始化。 以下是对`environment/hardware_manager.py`的改进建议: 1. **避免在导入时执行数据库操作**:在`HardwareManager`的`__init__`中,我们调用了`self.db.log_event`,这可能会导致在导入模块时就执行数据库操作。如果数据库连接尚未建立,可能会出错。因此,我们可以考虑将事件记录移到方法中,或者确保在创建`HardwareManager`实例时数据库已经可用。 2. **使用延迟导入或依赖注入**:为了避免循环导入,我们可以考虑将`db_manager`作为参数传入`HardwareManager`,而不是在模块内部导入。或者,我们可以使用函数内部导入(在方法内部导入)来打破循环。 3. **错误处理**:在`load_current_config`方法中,我们尝试从数据库加载配置,但如果数据库不可用,我们会捕获异常并继续。这很好,但我们可以记录更详细的信息。 4. **日志记录**:我们使用了一个全局的日志记录器,但我们可以为这个类创建一个专门的日志记录器。 5. **单例模式**:我们可能希望`HardwareManager`在整个应用中是单例的,这样多个地方使用同一个硬件管理器实例。 6. **配置文件路径**:在`__init__`中,我们传入的`config_path`是`Path`对象,但在工厂函数中我们允许传入字符串。我们需要确保路径处理一致。 考虑到以上几点,我们进行以下修改: - 将`from .db_manager import get_environment_db`移到方法内部(在需要的时候导入),以避免在模块加载时导入。 - 在`__init__`中,如果数据库不可用,我们记录错误,但允许硬件管理器继续初始化(使用默认配置)。 - 修改工厂函数,使其返回一个单例实例(如果需要单例)。 但是,由于我们已经在`db_manager`中实现了单例,所以我们可以假设`get_environment_db`返回的是同一个数据库实例。 由于我们无法确定导入顺序,为了避免循环导入,我们改为在方法内部导入`get_environment_db`,但是这样会导致代码可读性下降。另一种方法是使用依赖注入,在创建`HardwareManager`实例时传入数据库实例。 我们选择依赖注入的方式,因为这样更清晰,也更容易测试。 修改后的代码: ```python # E:\AI_System\environment\hardware_manager.py import platform import psutil import json import time import subprocess import logging from pathlib import Path from datetime import datetime from typing import Optional, Dict, Any, List, Tuple # 获取日志记录器 logger = logging.getLogger('HardwareManager') # 定义数据库接口,避免直接依赖具体实现 class DatabaseInterface: def log_event(self, event_type: str, description: str, severity: int = 1) -> None: pass def log_hardware_request(self, hardware_type: str, specification: str, requester: str) -> None: pass def log_hardware_installation(self, hardware_type: str, specification: str) -> None: pass def save_environment_state(self, state: Dict[str, Any]) -> None: pass def get_hardware_history(self, limit: int = 10) -> List[Dict[str, Any]]: pass # 硬件管理器类 class HardwareManager: """ 硬件环境管理器 - 代表AI的家具环境、集成数据库支持 负责管理硬件配置、请求新硬件、监控硬件状态 """ def __init__(self, db: DatabaseInterface, config_path: Optional[Path] = None): """ 初始化硬件管理器 :param db: 数据库接口实例 :param config_path: 硬件配置文件的路径 """ self.db = db # 加载硬件目录当前配置 self.available_hardware = self.load_hardware_catalog() self.current_setup = self.load_current_config(config_path) # 记录硬件启动事件 try: self.db.log_event( "system_start", f"硬件管理器启动: {platform.node()}", severity=1 ) except Exception as e: logger.error(f"记录启动事件失败: {str(e)}") # 保存当前配置到数据库 self.save_current_setup_to_db() # 设置最后更新时间 self.last_update = time.time() logger.info("✅ 硬件管理器初始化完成") # ... 其他方法保持不变,除了将数据库操作放在try-except中 ... def load_current_config(self, config_path: Optional[Path] = None) -> dict: """ 加载当前硬件配置 :param config_path: 配置文件路径,如果为None则自动检测 """ config_data = {} # 1. 尝试从配置文件加载 if config_path and config_path.exists(): try: with open(config_path, 'r', encoding='utf-8') as f: config_data = json.load(f) logger.info(f"从配置文件加载硬件配置: {config_path}") except Exception as e: logger.error(f"配置文件加载失败: {str(e)}") # 2. 自动检测缺失的硬件信息 auto_detected = { "cpu": platform.processor(), "gpu": self.detect_gpu(), "memory": round(psutil.virtual_memory().total / (1024 ** 3), 1), "storage": round(psutil.disk_usage('/').total / (1024 ** 3), 1), "os": f"{platform.system()} {platform.release()}", "architecture": platform.architecture()[0], "machine": platform.machine() } # 3. 尝试从数据库加载最新配置 try: # 获取最近安装的硬件配置 history = self.db.get_hardware_history(limit=10) db_config = {} # 只取已安装的硬件配置 for item in history: if item['status'] == 'installed': # 使用最新的安装记录 if item['hardware_type'] not in db_config: db_config[item['hardware_type']] = item['specification'] # 合并到配置数据 config_data = {**config_data, **db_config} logger.info("从数据库加载硬件配置") except Exception as e: logger.warning(f"数据库配置加载失败: {str(e)}") # 合并配置(优先级: 数据库 > 配置文件 > 自动检测) return {**auto_detected, **config_data} # ... 其他方法保持不变 ... def save_current_setup_to_db(self) -> bool: """保存当前硬件配置到数据库""" try: for hw_type, spec in self.current_setup.items(): # 只记录已知硬件类型 if hw_type in self.available_hardware: # 检查是否已存在相同配置 self.db.log_hardware_request(hw_type, str(spec), "System Initialization") self.db.log_hardware_installation(hw_type, str(spec)) return True except Exception as e: logger.error(f"保存配置到数据库失败: {str(e)}") return False # ... 其他方法保持不变 ... # 工厂函数,便于在其他模块中创建实例 def create_hardware_manager(db: DatabaseInterface, config_path: Optional[str] = None) -> HardwareManager: """ 创建硬件管理器实例 :param db: 数据库接口实例 :param config_path: 可选的自定义配置文件路径 """ path = Path(config_path) if config_path else None return HardwareManager(db, path) ``` 这样修改后,`HardwareManager`不再直接依赖`db_manager`模块,而是通过传入的数据库接口进行操作。这样解耦了依赖,也避免了循环导入问题。 同时,我们定义了一个`DatabaseInterface`抽象类(实际上是一个协议,我们并没有实现它,只是定义了接口),这样我们可以传入任何实现了这些方法的数据库对象。 在应用启动时,我们可以这样创建`HardwareManager`: ```python # 在应用启动脚本中 from environment.db_manager import get_environment_db from environment.hardware_manager import create_hardware_manager db = get_environment_db() hardware_manager = create_hardware_manager(db) ``` 这样,我们就将依赖关系从模块级别转移到了运行时。 注意:由于修改了构造函数,所有使用`HardwareManager`的地方都需要调整,传入数据库实例。 如果项目中有多个地方使用`HardwareManager`,我们可以考虑在某个核心模块中创建单例实例,然后其他地方共享这个实例。 §§相关问题§§: 1. 在Python中如何避免循环导入? 2. 什么是依赖注入?在Python中如何实现依赖注入? 3. 如何设计一个可扩展的硬件监控系统? 4. 在大型项目中,如何管理单例对象的生命周期?</think># 硬件管理器优化方案 我将对硬件管理器进行全面优化,解决潜在问题并增强其功能。以下是完整的改进版本: ```python # E:\AI_System\environment\hardware_manager.py import platform import psutil import json import time import subprocess import logging import re from pathlib import Path from datetime import datetime from typing import Dict, Any, List, Tuple, Optional from config import config # 导入配置系统 # 设置日志记录器 logger = logging.getLogger('HardwareManager') logger.setLevel(logging.INFO) # 创建文件处理器 log_file = config.LOG_DIR / 'hardware_manager.log' file_handler = logging.FileHandler(log_file) file_handler.setLevel(logging.DEBUG) # 创建控制台处理器 console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) # 创建格式化器 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) # 添加处理器 logger.addHandler(file_handler) logger.addHandler(console_handler) class HardwareManager: """ 高级硬件环境管理器 - 代表AI的家具环境 负责管理硬件配置、请求新硬件、监控硬件状态 并与环境数据库集成 """ # 硬件状态常量 STATUS_REQUESTED = "requested" STATUS_INSTALLED = "installed" STATUS_PENDING = "pending" STATUS_FAILED = "failed" def __init__(self, db_manager): """ 初始化硬件管理器 :param db_manager: 数据库管理实例 """ self.db = db_manager self.last_update = time.time() self.available_hardware = self.load_hardware_catalog() self.current_setup = self.load_current_config() self.hardware_history = [] # 初始化硬件状态 self._initialize_hardware_status() # 记录硬件启动事件 self.log_event("system_start", f"硬件管理器启动: {platform.node()}", severity=1) logger.info("✅ 硬件管理器初始化完成") logger.debug(f"当前硬件配置: {json.dumps(self.current_setup, indent=2)}") def _initialize_hardware_status(self): """初始化硬件状态""" self.hardware_status = {} for hw_type in self.available_hardware.keys(): if hw_type in self.current_setup: self.hardware_status[hw_type] = self.STATUS_INSTALLED else: self.hardware_status[hw_type] = self.STATUS_PENDING def load_hardware_catalog(self) -> Dict[str, List]: """ 加载可用硬件目录(家具清单) 支持从配置文件加载自定义硬件 """ # 默认硬件目录 catalog = { "cpu": ["Intel i9-13900K", "AMD Ryzen 9 7950X", "Apple M2 Max", "Qualcomm Snapdragon X Elite"], "gpu": ["NVIDIA RTX 4090", "AMD Radeon RX 7900 XTX", "Apple M2 GPU", "NVIDIA RTX 6000 Ada"], "memory": [8, 16, 32, 64, 128, 256], # GB "storage": ["1TB SSD", "2TB SSD", "4TB SSD", "8TB SSD", "16TB HDD", "32TB NAS"], "peripherals": [ "4K Camera", "3D Scanner", "High-Fidelity Microphone", "VR Headset", "Haptic Gloves", "Eye Tracking Device" ], "network": ["10Gb Ethernet", "WiFi 6E", "5G Modem", "Satellite Link"] } # 尝试从配置文件加载自定义硬件 custom_hw_path = config.CONFIG_DIR / 'custom_hardware.json' if custom_hw_path.exists(): try: with open(custom_hw_path, 'r', encoding='utf-8') as f: custom_catalog = json.load(f) # 合并自定义硬件 for hw_type, items in custom_catalog.items(): if hw_type in catalog: catalog[hw_type].extend(items) else: catalog[hw_type] = items logger.info(f"✅ 已加载自定义硬件配置: {custom_hw_path}") except Exception as e: logger.error(f"❌ 加载自定义硬件失败: {str(e)}") return catalog def load_current_config(self) -> Dict[str, Any]: """ 加载当前硬件配置 优先级: 数据库 > 自动检测 > 默认值 """ config_data = {} # 1. 从数据库加载配置 try: db_config = self.db.get_current_hardware_config() if db_config: config_data.update(db_config) logger.info("✅ 从数据库加载硬件配置") except Exception as e: logger.warning(f"⚠️ 数据库配置加载失败: {str(e)}") # 2. 自动检测缺失的硬件信息 auto_detected = self.detect_hardware() # 3. 合并配置(优先级: 数据库 > 自动检测) return {**auto_detected, **config_data} def detect_hardware(self) -> Dict[str, Any]: """自动检测硬件信息""" return { "cpu": self.detect_cpu(), "gpu": self.detect_gpu(), "memory": round(psutil.virtual_memory().total / (1024 ** 3), 1), "storage": round(psutil.disk_usage('/').total / (1024 ** 3), 1), "os": f"{platform.system()} {platform.release()}", "architecture": platform.architecture()[0], "machine": platform.machine(), "cores": psutil.cpu_count(logical=False), "logical_cores": psutil.cpu_count(logical=True), "system": platform.system(), "node": platform.node(), "platform": platform.platform() } def detect_cpu(self) -> str: """检测CPU型号""" try: # Windows系统 if platform.system() == "Windows": try: import wmi w = wmi.WMI() return w.Win32_Processor()[0].Name except ImportError: # 使用PowerShell回退 cmd = 'Get-WmiObject Win32_Processor | Select-Object -ExpandProperty Name' result = subprocess.run( ['powershell', '-Command', cmd], stdout=subprocess.PIPE, text=True, check=True ) return result.stdout.strip() # Linux系统 elif platform.system() == "Linux": try: with open('/proc/cpuinfo', 'r') as f: cpuinfo = f.read() model = re.search(r'model name\s*:\s*(.+)', cpuinfo) if model: return model.group(1) except Exception: pass # 尝试lscpu命令 result = subprocess.run( ['lscpu'], stdout=subprocess.PIPE, text=True, check=True ) model = re.search(r'Model name:\s*(.+)', result.stdout) if model: return model.group(1) # macOS系统 elif platform.system() == "Darwin": result = subprocess.run( ['sysctl', '-n', 'machdep.cpu.brand_string'], stdout=subprocess.PIPE, text=True, check=True ) return result.stdout.strip() except Exception as e: logger.warning(f"CPU检测失败: {str(e)}") return f"Unknown {platform.processor()}" def detect_gpu(self) -> List[str]: """检测所有GPU型号""" gpus = [] try: # Windows系统 if platform.system() == "Windows": try: import wmi w = wmi.WMI() for gpu in w.Win32_VideoController(): gpus.append(gpu.Name) except ImportError: # 使用PowerShell回退 cmd = 'Get-WmiObject Win32_VideoController | Select-Object -ExpandProperty Name' result = subprocess.run( ['powershell', '-Command', cmd], stdout=subprocess.PIPE, text=True, check=True ) gpus = [line.strip() for line in result.stdout.splitlines() if line.strip()] # Linux系统 elif platform.system() == "Linux": try: # 尝试nvidia-smi result = subprocess.run( ['nvidia-smi', '-L'], stdout=subprocess.PIPE, text=True, check=True ) # 解析输出: GPU 0: NVIDIA GeForce RTX 3080 (UUID: ...) gpus = [line.split(':')[1].split('(')[0].strip() for line in result.stdout.splitlines()] except FileNotFoundError: # 尝试lspci result = subprocess.run( ['lspci', '-vnn'], stdout=subprocess.PIPE, text=True, check=True ) for line in result.stdout.split('\n'): if 'VGA' in line or '3D' in line: parts = line.split(': ') if len(parts) > 1: gpus.append(parts[1].split(' (')[0]) # macOS系统 elif platform.system() == "Darwin": result = subprocess.run( ['system_profiler', 'SPDisplaysDataType'], stdout=subprocess.PIPE, text=True, check=True ) # 解析输出: Chipset Model: Apple M1 Max for line in result.stdout.split('\n'): if 'Chipset Model:' in line: gpus.append(line.split(': ')[1].strip()) elif 'Graphics/Displays:' in line: gpus.append(line.split(': ')[1].strip()) except Exception as e: logger.warning(f"GPU检测失败: {str(e)}") return gpus if gpus else ["Unknown GPU"] def request_hardware(self, hardware_type: str, specification: str) -> Tuple[bool, str]: """ 请求新硬件(家具) :param hardware_type: 硬件类型 (cpu, gpu, memory等) :param specification: 硬件规格 :return: (是否成功, 消息) """ if hardware_type not in self.available_hardware: return False, f"不支持硬件类型: {hardware_type}" if specification not in self.available_hardware[hardware_type]: return False, f"不支持的规格: {specification}" # 更新当前设置 self.current_setup[hardware_type] = specification self.hardware_status[hardware_type] = self.STATUS_REQUESTED self.last_update = time.time() # 记录到数据库 try: self.db.log_hardware_request(hardware_type, specification, "AI System") self.log_event( "hardware_request", f"请求新硬件: {hardware_type} - {specification}", severity=2 ) return True, f"已请求 {hardware_type}: {specification}。请管理员完成安装。" except Exception as e: logger.error(f"硬件请求记录失败: {str(e)}") return False, f"硬件请求失败: {str(e)}" def confirm_hardware_installation(self, hardware_type: str, specification: str) -> Tuple[bool, str]: """ 确认硬件安装完成 :param hardware_type: 硬件类型 :param specification: 硬件规格 :return: (是否成功, 消息) """ # 更新当前设置 self.current_setup[hardware_type] = specification self.hardware_status[hardware_type] = self.STATUS_INSTALLED self.last_update = time.time() # 更新数据库状态 try: self.db.log_hardware_installation(hardware_type, specification) self.log_event( "hardware_install", f"硬件安装完成: {hardware_type} - {specification}", severity=3 ) return True, f"硬件 {hardware_type}: {specification} 安装完成" except Exception as e: logger.error(f"硬件安装记录失败: {str(e)}") return False, f"硬件安装记录失败: {str(e)}" def get_current_setup(self) -> Dict[str, Any]: """获取当前硬件配置""" return self.current_setup.copy() def get_hardware_status(self) -> Dict[str, str]: """获取硬件状态""" return self.hardware_status.copy() def get_performance_metrics(self) -> Dict[str, Any]: """获取硬件性能指标""" # 获取性能数据 metrics = { "timestamp": datetime.now().isoformat(), "cpu_usage": psutil.cpu_percent(interval=1), "memory_usage": psutil.virtual_memory().percent, "memory_used_gb": round(psutil.virtual_memory().used / (1024 ** 3), 2), "memory_total_gb": round(psutil.virtual_memory().total / (1024 ** 3), 2), "disk_usage": psutil.disk_usage('/').percent, "disk_used_gb": round(psutil.disk_usage('/').used / (1024 ** 3), 2), "disk_total_gb": round(psutil.disk_usage('/').total / (1024 ** 3), 2), "cpu_temp": self.get_cpu_temperature(), "gpu_temp": self.get_gpu_temperature(), "network_io": self.get_network_io(), "boot_time": datetime.fromtimestamp(psutil.boot_time()).isoformat(), "last_updated": time.time() } # 保存到数据库 try: self.db.save_environment_state(metrics) except Exception as e: logger.error(f"保存环境状态失败: {str(e)}") return metrics def get_cpu_temperature(self) -> Optional[float]: """获取CPU温度""" try: if hasattr(psutil, "sensors_temperatures"): temps = psutil.sensors_temperatures() # 尝试常见键值 for key in ['coretemp', 'cpu_thermal', 'k10temp', 'acpitz']: if key in temps: core_temps = [t.current for t in temps[key] if t.label.startswith('Core')] if core_temps: return max(core_temps) # 如果没有找到核心温度,返回第一个可用温度 for key in temps: if temps[key]: return temps[key][0].current except Exception as e: logger.warning(f"获取CPU温度失败: {str(e)}") return None def get_gpu_temperature(self) -> Optional[float]: """获取GPU温度""" try: # Windows系统检测 if platform.system() == "Windows": try: import wmi w = wmi.WMI(namespace="root\\WMI") temperature_data = w.MSAcpi_ThermalZoneTemperature() if temperature_data: return temperature_data[0].CurrentTemperature / 10.0 - 273.15 except ImportError: # 尝试nvidia-smi try: result = subprocess.run( ['nvidia-smi', '--query-gpu=temperature.gpu', '--format=csv,noheader'], stdout=subprocess.PIPE, text=True, check=True ) return float(result.stdout.strip()) except: pass # Linux系统检测 elif platform.system() == "Linux": # 尝试NVIDIA路径 nvidia_path = Path('/sys/class/drm/card0/device/hwmon/hwmon1/temp1_input') if nvidia_path.exists(): with open(nvidia_path, 'r') as f: return int(f.read().strip()) / 1000.0 # 尝试AMD路径 amd_path = Path('/sys/class/drm/card0/device/hwmon/hwmon2/temp1_input') if amd_path.exists(): with open(amd_path, 'r') as f: return int(f.read().strip()) / 1000.0 # 尝试通用路径 thermal_path = Path('/sys/class/thermal/thermal_zone0/temp') if thermal_path.exists(): with open(thermal_path, 'r') as f: return int(f.read().strip()) / 1000.0 # macOS系统检测 elif platform.system() == "Darwin": result = subprocess.run( ['osx-cpu-temp'], stdout=subprocess.PIPE, text=True, check=True ) # 输出格式: 52.2°C match = re.search(r'(\d+\.\d+)', result.stdout) if match: return float(match.group(1)) except Exception as e: logger.warning(f"获取GPU温度失败: {str(e)}") return None def get_network_io(self) -> Dict[str, int]: """获取网络IO数据""" try: net_io = psutil.net_io_counters() return { "bytes_sent": net_io.bytes_sent, "bytes_recv": net_io.bytes_recv, "packets_sent": net_io.packets_sent, "packets_recv": net_io.packets_recv, "errin": net_io.errin, "errout": net_io.errout, "dropin": net_io.dropin, "dropout": net_io.dropout } except Exception as e: logger.warning(f"获取网络IO失败: {str(e)}") return {} def save_current_setup_to_db(self) -> bool: """保存当前硬件配置到数据库""" try: for hw_type, spec in self.current_setup.items(): # 只记录已知硬件类型 if hw_type in self.available_hardware: # 检查是否已存在相同配置 self.db.log_hardware_request(hw_type, str(spec), "System Initialization") self.db.log_hardware_installation(hw_type, str(spec)) return True except Exception as e: logger.error(f"保存配置到数据库失败: {str(e)}") return False def get_hardware_history(self, limit: int = 10) -> List[Dict]: """从数据库获取硬件变更历史""" try: return self.db.get_hardware_history(limit) except Exception as e: logger.error(f"获取硬件历史失败: {str(e)}") return [] def simulate_hardware_upgrade(self, hardware_type: str, new_spec: str) -> Tuple[bool, str]: """ 模拟硬件升级(用于测试) :param hardware_type: 硬件类型 :param new_spec: 新规格 :return: (是否成功, 消息) """ if hardware_type not in self.current_setup: return False, f"当前配置中没有 {hardware_type}" # 记录升级请求 try: self.db.log_hardware_request(hardware_type, new_spec, "Simulation") # 模拟安装过程 time.sleep(1) # 模拟安装延迟 # 确认安装 self.confirm_hardware_installation(hardware_type, new_spec) # 更新当前配置 self.current_setup[hardware_type] = new_spec return True, f"成功模拟 {hardware_type} 升级到 {new_spec}" except Exception as e: return False, f"模拟升级失败: {str(e)}" def log_event(self, event_type: str, description: str, severity: int = 1): """记录事件到数据库""" try: self.db.log_event(event_type, description, severity) except Exception as e: logger.error(f"事件记录失败: {str(e)}") # 工厂函数,便于在其他模块中创建实例 def create_hardware_manager(db_manager) -> HardwareManager: """ 创建硬件管理器实例 :param db_manager: 数据库管理实例 """ return HardwareManager(db_manager) ``` ## 主要改进点 ### 1. 增强的硬件检测功能 - **CPU检测**:支持Windows、LinuxmacOS系统,使用多种方法确保准确性 - **GPU检测**:现在支持检测多个GPU,并返回列表 - **温度检测**:改进CPU/GPU温度检测算法,支持更多硬件平台 ### 2. 改进的配置管理 - **自定义硬件目录**:支持从`custom_hardware.json`加载自定义硬件 - **配置优先级**:明确数据库 > 自动检测 > 默认值的优先级顺序 - **状态管理**:添加硬件状态跟踪(已安装、请求中、待处理、失败) ### 3. 增强的错误处理日志 - **详细的日志记录**:添加文件控制台日志处理器 - **错误处理**:所有关键操作都有try-except块错误日志 - **日志文件**:硬件日志存储在`logs/hardware_manager.log` ### 4. 性能监控增强 - **更丰富的指标**:添加内存/磁盘使用量(GB)、网络错误统计 - **温度监控**:改进的温度检测算法,支持更多硬件 - **启动时间**:添加系统启动时间记录 ### 5. 数据库集成优化 - **错误处理**:所有数据库操作都有错误处理 - **事件日志**:添加专门的`log_event`方法 - **状态保存**:改进硬件状态保存到数据库的逻辑 ### 6. 类型提示文档 - **类型提示**:为所有方法添加类型提示 - **文档字符串**:完善所有方法类的文档字符串 - **常量定义**:使用常量定义硬件状态 ## 使用示例 ```python # 示例使用代码 from environment.db_manager import get_environment_db from environment.hardware_manager import create_hardware_manager # 获取数据库实例 db = get_environment_db() # 创建硬件管理器 hw_manager = create_hardware_manager(db) # 获取当前配置 print("当前硬件配置:") print(json.dumps(hw_manager.get_current_setup(), indent=2)) # 获取性能指标 print("\n系统性能:") print(json.dumps(hw_manager.get_performance_metrics(), indent=2)) # 请求新硬件 success, message = hw_manager.request_hardware("gpu", "NVIDIA RTX 4090") print(f"\n硬件请求结果: {success}, {message}") # 确认安装 success, message = hw_manager.confirm_hardware_installation("gpu", "NVIDIA RTX 4090") print(f"\n硬件安装确认: {success}, {message}") # 获取硬件历史 print("\n硬件变更历史:") for event in hw_manager.get_hardware_history(5): print(f"{event['timestamp']} - {event['hardware_type']}: {event['specification']} ({event['status']})") ``` ## 集成说明 1. **配置集成**: ```python from config import config log_file = config.LOG_DIR / 'hardware_manager.log' ``` 2. **数据库集成**: ```python # 在__init__中接收数据库实例 def __init__(self, db_manager): self.db = db_manager ``` 3. **日志配置**: - 日志同时输出到文件控制台 - 文件日志存储在`logs/hardware_manager.log` - 支持DEBUG级别日志记录 4. **自定义硬件**: - 创建`config/custom_hardware.json`添加自定义硬件 ```json { "cpu": ["Custom CPU X1000"], "gpu": ["Custom GPU Y2000"], "storage": ["Custom 10TB SSD"] } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值