赞
踩
前言:最近一直在做关于显卡数据采集的调研工作,也在github上看到了一些三方库比如Python和golang的psutil, python: gpustart,再或者通过wmi或者windowsApi等底层接口 但是都只能获取到显卡的名称以及厂家信息等 无法真正意义上获取到显卡占用率等数据 在或者只能获取到英伟达的显卡数据 (该数据都是通过英伟达所开放出来的命令工具所获取到的) 后通过阅读C++ 的一个windows插件 发现他在底层使用了一个叫openhardwaremonitor的动态库 后开始尝试
结果:
虽然可以在win系统上获取到amd和英伟达以及英特尔显卡的使用率 但是并不准确
结果虽然差强人意,但是起码指明了一道方向 后来通过github上查看该项目的描述时得知 该动态库是从另外一个库中迁移出来的分支 LibreHardwareMonitor
LibreHardwareMonitor
下载地址:下载LibreHardwareMonitor.dll
一个C#实线的可与底层系统进行交互的动态库
2.7start 被众多插件软件所引用
C#语言的动态库,那么在python中如何使用?
pythonnet (一个用python解析.net的三方库 实现了.dll文件的动态引用功能)
安装: pip install pythonnet
使用:
```python
import clr # pythonnet
clr.AddReference(dll)# 加载dll动态库
# 将需要使用的动态库通过 from import进行导入(因libreHardwareMonitor.lib没有文档 所以按照这种导入即可)
from LibreHardwareMonitor.Hardware import Computer
computer = Computer() # 正常实例化即可
```
我们如何知道LibreHardwareMonitor的参数都有哪些呢? 可以通过github上的描述进行查看 这是一个c#的示例
通过该示例 我们可以看到 关于computer初始化完成后有几个属性 可以控制当前.dll动态库对哪些数据进行获取
本次只对该3个参数进行使用, 感兴趣的可以去尝试一下另外4个参数
1. IsCpuEnabled 布尔值 获取CPU时为true
2. IsGpuEnabled 布尔值 获取GPU时为true
3. IsMemoryEnabled 布尔值 获取内存时为true
使用:
import clr import os, sys clr.AddReference(path + './LibreHardwareMonitorLib') # 这里不需要加后缀.dll 内部会自动拼接 from LibreHardwareMonitor.Hardware import Computer computer_tmp = Computer() # 实例这这个类 # computer_tmp.IsCpuEnabled = True # 获取CPU时用 computer_tmp.IsGpuEnabled = True # 获取GPU时用 # computer_tmp.IsMemoryEnabled = True # 获取内存时用 # self.computer_tmp.IsNetworkEnabled = True # 获取网卡数据时使用 computer_tmp.Open() print(len(computer_tmp.Hardware)) for computer in computer_tmp.Hardware: computer.Update() data_dict = [] for s in computer.Sensors: print("名称为:", s.Name) # print("元器件名称:", s.Identifier) print("类型为:", s.SensorType) print("值是:", s.Value) sensor_type = str(s.SensorType) if sensor_type == "Load": data_dict.append({ str(s.Name).replace("D3D ", ""): s.Value }) print(data_dict)
结果:
参数:
Hardware:对应python中的列表 对应的是Computer中为true的属性值
Hardware[index].Sensors : 对应的是获取到的具体数据
属性:
Name: 元器件名称
Identifier:资源标识符
SensorType:硬件类型 想起查看下方描述
Parent: 所属父级元器件
Hardware[index].Sensors.SensorType:当前获取到的数据类型(如果存在则显示)
具体实现:
FastApi: 异步web开发框架,提供api访问
pythonnet: 访问.dll文件获取底层交互能力
psutil: 获取内存的具体使用(LibreHardwareMonitor只提供了负载值 未提供对应的总内存以及使用内存的详细值)
完整代码main.py
import uvicorn from fastapi import FastAPI, APIRouter from fastapi.middleware.cors import CORSMiddleware import clr import yaml, os, sys import psutil from starlette.responses import JSONResponse sys.path.append(os.getcwd()) app = FastAPI(title="设备信息获取", description="用于获取windows下显卡,内存,cpu,网卡等使用情况", version="v0.1") class GetDeviceInfo: def __init__(self, dll: str): clr.AddReference(dll) from LibreHardwareMonitor.Hardware import Computer self.computer_tmp = Computer() # 实例这这个类 self.computer_tmp.IsCpuEnabled = True # 获取CPU温度时用 self.computer_tmp.IsGpuEnabled = True # 获取GPU温度时用 self.computer_tmp.IsMemoryEnabled = True # 获取内存时用 # self.computer_tmp.IsNetworkEnabled = True # 获取网卡时用 self.computer_tmp.Open() @staticmethod def memory_info()->tuple: p = psutil.virtual_memory() return p.total / 1024 / 1024, p.used / 1024 / 1024 def params_hardware(self, index: int) -> dict: hard = self.computer_tmp.Hardware[index] hard.Update() device_data = {} for i in hard.Sensors: sensor_type = str(i.SensorType) if sensor_type == "Load" and sensor_type not in device_data: device_data["Name"] = hard.Name device_data["Load"] = i.Value if index == 2 and "/temperature" in str(i.Identifier): device_data["temperature"] = i.Value if sensor_type == "Load" and index == 2: device_data[str(i.Name).replace("D3D ", "")] = i.Value if index == 1: total, used = self.memory_info() device_data['total'] = total device_data['used'] = used return device_data def run(self): data_list = [] type_list = ["CPU", "memory", "GPU"] com_len = len(self.computer_tmp.Hardware) if com_len > len(type_list): number = com_len - len(type_list) [type_list.append("other" + str(i)) for i in range(number)] for index in range(com_len): device_info = self.params_hardware(index) device_info['type'] = type_list[index] data_list.append(device_info) return data_list class Router: routerApi = APIRouter() def __init__(self): # 如果使用Pyinstaller -F 进行编译时,将这里放开, 解决相对路径下找不到可用的.dll文件问题 # path = os.path.dirname(sys.executable) # self.device = GetDeviceInfo(path + "/lib/LibreHardwareMonitorLib") self.device = GetDeviceInfo("./lib/LibreHardwareMonitorLib") async def get_device_info(self): return JSONResponse( status_code=200, content={ "message": "success!", "code": 200, "data": self.device.run() } ) def router_list(self): self.routerApi.add_api_route("/deviceInfo", self.get_device_info, methods=["GET"]) def init_service(): # 处理浏览器请求时会出现跨域情况 app.add_middleware(CORSMiddleware, allow_origins="*", allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) router = Router() router.router_list() app.include_router(router.routerApi, prefix="/device") init_service() if __name__ == '__main__': # 也可通过配置文件配置相关启动的host以及域名 #with open("config/config.yaml", mode='r+', encoding='utf-8') as f: # data = yaml.load(f.read(), Loader=yaml.Loader) uvicorn.run("__main__:app", host="0.0.0.0", port=9969)
接口:
GET http://localhost:9969/device/deviceInfo
结果:
该服务可直接运行 也可编译后通过.exe进行运行 当前仅支持windows下 暂未支持linux以及mac
已上传至https://github.com/yuanhuihui1203/GetDeviceInfo 各位大佬可以点击一下start支持!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。