wails+vue3实现一个简单Monitor

news2024/11/28 2:34:09

介绍

本来呢最近是在学Rust,顺便看看Tauri相关的内容.然后刷评论区突然看到有人提到go生态中也有类似的框架—Wails,所以下午花了点时间来动手玩一下.

首先看一下最终的运行效果,前端样式懒得调整所以界面很丑只是实现一下功能

image-20230626202755134

开始

这次的目标就是做一个功能类似于nvidia-smi的桌面工具,另外整合一下cpu的使用情况.说明一下所利用到的相关库,关于CPU资源利用gopsutil来得到,GPU相关信息则是使用go-nvml(目前仅仅支持linux,原本想利用wails跨平台编译一个windows exe结果不支持就此作罢);前端界面除了wails本身的vue模板,可视化利用vue3-apexcharts.

大致思路:

  1. 实现后端逻辑,得到相关数据
  2. 实现前端界面
  3. 前后端交互实现动态数据更新

1 后端逻辑

根据相关库的介绍,我们可以简单实现相应数据的获取,这里拿GPU中计算利用率为例

首先我们需要一个全局的nvml device,由于主机只有一张显卡所以没有考虑利用count循环而是直接指定index(0)作为device.

ret = nvml.Init()
if ret != nvml.SUCCESS {
log.Fatalf("init failed %v", nvml.ErrorString(ret))
}
​
device, ret = nvml.DeviceGetHandleByIndex(0)

这里没有defer nvml.shutdown()因为是一直更新,所以当函数退出但是goroutine依旧在运行,后期就无法得到device出错.

再来考虑数据方面,因为我想观察usage的变化,因此得设计一个类数组容器来记录每次得到的值,同时为了保证不会无限增长所以得设置最大长度.一开始考虑用数组或者切片,但是这无可避免会导致后期持续更新数据的时候每次都需要copy,无端消耗性能与内存空间.所以想到用循环队列,这样只需要更新队首与队尾,而且占用内存并不会产生增长.

type CircularQueue struct {
    slice []uint32
    front int
    size  int
    count int
}
​
func newCircularQueue(maxSize int) *CircularQueue {
    return &CircularQueue{
        slice: make([]uint32, maxSize),
        front: 0,
        size:  maxSize,
        count: 0,
    }
}
​
func (cq *CircularQueue) enqueue(element uint32) {
    if cq.count == cq.size {
        cq.front = (cq.front + 1) % cq.size
        cq.count--
    }
    rear := (cq.front + cq.count) % cq.size
    cq.slice[rear] = element
    cq.count++
}
​
func (cq *CircularQueue) getSlice() []uint32 {
    if cq.count == 0 {
        return nil
    }
​
    slice := make([]uint32, cq.count)
    for i := 0; i < cq.count; i++ {
        slice[i] = cq.slice[(cq.front+i)%cq.size]
    }
    return slice
}

通过循环队列,我们每次请求元素并将元素入队,最终返回只需要利用getSlice()方法返回队列中的数据即可.具体得到GPU Usage数据的代码如下

const MAXSIZE = 10
​
var GpuUsagecq = newCircularQueue(MAXSIZE)
​
func (a *App) GetGpuUsage() []uint32 {
    rwmutex.RLock()
    utilization, ret := device.GetUtilizationRates()
    rwmutex.RUnlock()
    if ret != nvml.SUCCESS {
        log.Fatalf("Unable to get utilization of device at index %d: %v", 0, nvml.ErrorString(ret))
    }
    GpuUsagecq.enqueue(utilization.Gpu)
    return GpuUsagecq.getSlice()
}

这里为了保证并发安全还是用了一下读锁,不过感觉读操作的话用不用应该问题不大.这里使用device.XXX()就可以得到GPU当前的各种信息,具体可以去看api文档.按照相似的逻辑,就可以得到我们所需要的所有信息数据.

2 前端界面

这里我们使用vue3-apexcharts,不过由于我的前端技术很菜,对于vue3也只是大致了解过,因此这部分我也不太好详细简介,更多是对着官网中的demo修改.在frontend/src/components下创建一个组件Monitor,然后写一下template

<template>
  <div>
    <div class="chart-row">
      <apexchart
          v-for="(chartOptions, index) in areaChartOptions"
          :key="index"
          type="area"
          :options="chartOptions"
          :series="areaChartSeries[getChartId(index)]"
          class="chart-column"
      />
    </div>
​
    <div class="chart-row">
      <apexchart type="donut" :options="DonutOptions" :series="donutSeries" />
      <apexchart type="radialBar" :options="radialOptions" :series="radialSeries" />
    </div>
​
  </div>
</template>

在下面data()中设置好options和series初始值,运行wails dev就能看到一个静态的页面.

3 前后端交互

这部分我感觉wails文档中写的并不好,没有任何很详细的例子指出运行时的前后端数据如何交互.参考官网介绍中唯一可以参考的Events事件配合如何工作,自己慢慢体会写出来.

首先来看后端部分,第一部分中我们实现了所有数据的获取,这里我们只需要让数据获取持续运行(刷新间隔自定义)并且将数据传给前端.

go func() {
    for {
        runtime.EventsEmit(a.ctx, "GetCpuUsage", a.GetCpuUsage())
        runtime.EventsEmit(a.ctx, "GetGpuMem", a.GetGpuMem())
        runtime.EventsEmit(a.ctx, "GetGpuUsage", a.GetGpuUsage())
        time.Sleep(100 * time.Millisecond)
    }
}()
​
go func() {
    for {
        runtime.EventsEmit(a.ctx, "GetFans", a.GetFans())
        runtime.EventsEmit(a.ctx, "GetTemperature", a.GetTemperature())
        time.Sleep(3 * time.Second)
    }
}()

我希望关于usage以及memory的信息刷新更及时,而温度和风扇转速这些貌似不太重要的信息可以慢一点.然后通过EventsEmit将数据与事件传递给前端,而前端设置一下EventsOn事件监听,实现数据接收并完成前端界面数据更新.

EventsOn("GetGpuUsage",GetGpuUsage=>{
      if(GetGpuUsage){
        this.areaChartSeries['area-chart-1'][0].data=GetGpuUsage
      }
})

这样就最终实现了我们一开始的界面内容.

最后

这一次尝试算是Tauri之前的一次小玩具,花了两个个小时从0学习wails以及一些前端库,最终也算拼凑出了最初设计的功能.wails最终打包出来的可执行文件大小仅仅只有2.8M,比起一些Electron打包出来的工具来说小了不止一点.

image-20230626211921724

另外我们可以在main.go中添加webview使用硬件加速,这样就可以让GPU usage不再一直是0%

Linux: &linux.Options{
            WebviewGpuPolicy: linux.WebviewGpuPolicyAlways,
},

最后放一张与watch -n0.1 nvidia-smi对比的图片作为结束
image-20230626212216574

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/719966.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#基础学习_字段与属性的比较

C#基础学习_字段与属性的比较 字段: 字段主要是为类的内部做数据交互使用,字段一般是private修饰; 字段可以赋值也可以读取; 当需要为外部提供数据的时候,请将字段封装为属性,而不是使用公有字段,这是面对对象编程所提倡的。 //字段:学号private int studentID;属性: …

语义分割大模型RSPrompter论文阅读

论文链接 RSPrompter: Learning to Prompt for Remote Sensing Instance Segmentation based on Visual Foundation Model 开源代码链接 RSPrompter 论文阅读 摘要 Abstract—Leveraging vast training data (SA-1B), the foundation Segment Anything Model (SAM) propo…

vue动态组件component详解

附上代码 <template><div class"export-full-data-manage"><div class"main"><div class"left"><ul><li v-for"item in menus" :key"item.value" :class"[item.valuecurrent?curre…

【UE5 Cesium】11-Cesium for Unreal 切换Dynamic Pawn为其它Pawn

前言 我们知道在Cesium for Unreal中默认使用的是DynamicPawn来浏览地图场景。DynamicPawn适用全球浏览&#xff0c;可以按自定义曲线进行飞行。但是DynamicPawn是使用的是地理参考坐标系&#xff0c;并不是标准的UE坐标系&#xff0c;当我们全球浏览结束后&#xff0c;可能需要…

2023年6月榜单丨飞瓜数据B站UP主排行榜(哔哩哔哩)发布!

飞瓜轻数发布2023年6月飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数三个维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能力强的B站UP主。 飞…

工作是EXCEL的天下

文章目录 EXCEL单元格内的换行筛选某一列的重复值批量删除重复值以某一列为联结&#xff0c;合并两个表格中的内容 本篇博文记录了笔者在工作中常用的EXCEL操作方法&#xff0c;持续更新中…… EXCEL单元格内的换行 AltEnter 筛选某一列的重复值 选中需要查找重复值的一列→…

如何在Microsoft Word中制作组织架构图

如果要说明公司或组织中的报告关系,可以创建一个使用组织结构图布局的 SmartArt 图形,如组织结构图。 注意:绘制组织结构图的另一种方法是使用 Microsoft 绘图应用程序 Visio。 使用 SmartArt 图形在 Excel、Outlook、PowerPoint 或 Word 中创建组织结构图,以显示组织中的…

磁盘镜像软件

什么是磁盘镜像 磁盘镜像是存储在计算机磁盘中的数据的副本或副本。磁盘镜像将包含数据存储设备的内容&#xff0c;并复制此类设备的结构。它还将包含操作系统分区。 磁盘镜像本质上是一种从主系统复制操作系统和存储在磁盘中的数据以将其分发到其他目标计算机的方法。自动化…

4.40ue4:样条线(轨迹)

1.创建样条线&#xff08;样条组建&#xff09; spline 多出一个点&#xff0c;按住alt拖住断点可以再生成一个点 可以在场景中拖动点编辑样条线 如果想要直角&#xff0c;可以点击细节面板找到spline组件&#xff0c;修改类型为linear&#xff0c;前后两点都需要改为绝对值&a…

3d渲染画面变形怎么办?

在用3dmax渲染图片时有时会遇到画面变形的情况&#xff0c;这个是什么原因呢&#xff1f;今天我们就来看看吧。 首先我们来看下变形的具体情况&#xff0c;再分析原因。可以看到整个画面都畸变了&#xff0c;呈现出上下拉伸的情况&#xff0c;能造成这个效果的&#xff0c;只有…

集合面试题详解

算法复杂度分析 List ArrayList 数据结构-数组 ArrayList源码分析 成员变量 构造方法 关键方法 ArrayList底层实现原理 如何实现数组和ArrayList之间的转换 LinkedList 单向链表 双向链表 ArrayList和LinkedList的区别 HashMap 二叉树 红黑树 散列表 HashMap的实现原理 Ha…

《C++ Primer》--学习12

动态内存 动态内存与智能指针 除了静态内存和栈内存&#xff0c;每个程序还拥有一个内存池。这部分内存被称为自由空间 或 堆&#xff0c;程序用堆来存储动态分配的对象 动态内存和智能指针 智能指针负责自动释放所指向的对象 shared_ptr 类 智能指针也是模板

一篇读懂React、vue框架的生命周期函数

当涉及到前端框架时&#xff0c;React 和 Vue.js 是两个非常受欢迎的选择。它们都提供了强大的工具和功能&#xff0c;帮助开发者构建交互式的、可扩展的应用程序。在这两个框架中&#xff0c;生命周期函数是一个重要的概念&#xff0c;它们允许我们在组件的不同阶段执行特定的…

车规芯片物理实现上的难度

在PR部分&#xff0c;车规级芯片的温度范围根据芯片工作位置不同也有所差别&#xff0c;最差的位置需要-40到150&#xff0c;除了DFM和功耗以及EM比较严格外&#xff0c;有些产品物理实现上对运算逻辑单元的位置也有特殊要求。 DFT部分才是车规级芯片的难点&#xff0c;感兴趣…

软件设计模式与体系结构-设计模式-行为型软件设计模式-迭代器模式

行为型软件设计模式 概述 行为型设计模式是软件设计模式中的一类&#xff0c;用于处理对象之间的交互和通信。这些模式关注的是对象之间的行为和职责分配。以下是几种常见的行为型设计模式&#xff1a; 观察者模式&#xff08;Observer Pattern&#xff09;&#xff1a;定义了…

【网络安全带你练爬虫-100练】第4练:添加异常处理代码

目录 一、异常处理代码&#xff1a; 二、执行结果&#xff1a; 三、完整代码&#xff1a; &#xff08;当代码越来越长的时候&#xff0c;异常处理代码有时候能起到很好的作用&#xff09; 一、异常处理代码&#xff1a; &#xff08;1&#xff09;try-except搭配&#xff…

Stable Difussion 解决绘图图片灰暗模糊,让图像色彩更丰富

在使用Stable Difussion进行AI绘画的时候&#xff0c;使用VAE能够产生许多有趣的效果。其滤镜功能可根据需要调整图像的色彩饱和度&#xff0c;使图像产生不同的视觉效果。 如下图所示&#xff1a; 但是如果不使用VAE那你的图像可能就会变得灰暗。 文章目录 VAE用途VAE的使…

cspm是什么?对比pmp怎么样?

一、国标项目管理&#xff08;项目管理专业人员能力评级&#xff09;证书是什么&#xff1f; 证书样式 《项目管理专业人员能力评价要求》&#xff08;GB/T 41831-2022&#xff09;是2022年10月12日开始实施的一项中国国家标准&#xff0c;归口于全国项目管理标准化技术委员会。…

【问题】TypeError: Cannot read properties of undefined (reading ‘getStackAddendum‘)

问题描述 项目运行中&#xff0c;控制台提示类型错误&#xff0c;无法读取未定义的属性getStackAddendum TypeError: Cannot read properties of undefined (reading getStackAddendum) 原因分析&#xff1a; 在上述截图的错误日志中&#xff0c;有执行validateChildKeys和va…

初识C++:从零开始掌握神秘之门的钥匙

&#x1f331;博客主页&#xff1a;青竹雾色间. &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ✨人生如寄&#xff0c;多忧何为 ✨ 目录 一、什么是C&#xff1f; 二、 C的发展史 三、C的重要性 3.1 语言的使用广泛度 3.2 在工作领域 3.2.1. 操作系…