wails+vue3实现一个简单Monitor

本文介绍了使用Go语言的Wails框架和相关库,如gopsutil和go-nvml,构建一个类似nvidia-smi的桌面工具,监控GPU和CPU的使用情况。开发者利用循环队列优化数据存储,确保内存效率,并通过vue3-apexcharts实现前端图表展示。文章还提到了前后端交互的实现方式以及Wails打包后的轻量级特性。
摘要由CSDN通过智能技术生成

介绍

本来呢最近是在学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

Wails一个用于构建跨平台桌面应用程序的开发工具包,它结合了Go语言和Web前端技术。通过使用Wails,您可以使用Go语言编写后端逻辑,并使用Web前端技术(如HTML、CSS和JavaScript)构建用户界面。 以下是使用Wails + Go的一些基本步骤: 1. 安装Wails CLI:您可以使用以下命令安装Wails CLI环境检测工具: ```shell go install github.com/wailsapp/wails/v2/cmd/wails@latest ``` 2. 创建新的Wails项目:使用以下命令创建一个新的Wails项目: ```shell wails init <project_name> ``` 这将在当前目录下创建一个新的Wails项目。 3. 编写Go后端代码:在Wails项目的`main.go`文件中,您可以编写Go语言的后端逻辑。您可以使用Go的强大功能来处理数据、执行计算等。 4. 构建前端界面:在Wails项目的`frontend`目录中,您可以使用Web前端技术(如HTML、CSS和JavaScript)构建用户界面。您可以使用任何您熟悉的前端框架或库,例如ant-design-vue。 5. 运行应用程序:使用以下命令在开发模式下运行应用程序: ```shell wails serve ``` 这将启动Wails开发服务器,并在浏览器中打开应用程序。 6. 打包应用程序:一旦您完成了应用程序的开发,您可以使用以下命令将其打包为可执行文件: ```shell wails build ``` 这将根据您的操作系统生成相应的可执行文件。 请注意,以上步骤只是Wails + Go的基本示例。您可以根据自己的需求和喜好进行更多的定制和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shelgi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值