Compare commits

...

4 Commits

Author SHA1 Message Date
ygxbnet 7f0e4fe607 perf(api): 提高并发请求限制并添加配置写入日志
构建上传工具 / build-tool (push) Successful in 1m40s
- 将并发请求限制从10提升到500
- 在配置写入时添加调试日志输出
2026-04-28 15:03:13 +08:00
ygxbnet 199bd43b00 feat(api): 优化HTTP连接池和并发控制
- 增加IdleConnTimeout从30秒到30分钟
- 添加并发请求限制通道,最大同时请求数为10
- 实现InitConn函数用于预创建连接池
- 在UploadDataToServer中添加请求限流控制
- 优化资源清理逻辑,使用defer确保响应体关闭
- 重命名runtime包别名以避免冲突
- 在uploader中添加连接池初始化日志
- 添加panic恢复机制和错误处理
2026-04-28 15:00:15 +08:00
ygxbnet 4addc29b2c refactor(config): 添加配置写入的并发安全锁机制
- 引入 sync.Mutex 确保配置访问的线程安全性
- 在 WriteConfig 函数中实现读写锁定机制
- 防止多协程同时修改配置导致的数据竞争问题
2026-04-28 14:59:21 +08:00
ygxbnet 7face117f3 refactor(App): 解决程序运行时重复写入配置
- 移除 watch 监听器,改用事件驱动方式保存配置
- 添加 writeServerUrl、writeToken 等配置保存方法
- 在表单项上绑定 change 事件触发配置保存
- 移除不再使用的 nextTick 导入
- 统一配置保存逻辑到独立函数中
2026-04-28 14:53:19 +08:00
5 changed files with 78 additions and 33 deletions
+1
View File
@@ -65,6 +65,7 @@ func (a *App) GetConfig() config.Config {
}
func (a *App) WriteConfig(key string, value any) {
fmt.Println("写入配置:", key, value)
config.WriteConfig(key, value)
}
+26 -26
View File
@@ -1,5 +1,5 @@
<script lang="ts" setup>
import {ref, nextTick, watch, computed} from 'vue'
import {ref, nextTick, computed} from 'vue'
import {ElMessage} from 'element-plus'
import {ElMessageBox} from 'element-plus'
import {SelectPath, GetConfig, WriteConfig, StartUpload, StopUpload} from '../wailsjs/go/main/App';
@@ -93,6 +93,25 @@ const clearLog = () => {
})
}
const writeServerUrl =() => {
WriteConfig("url", serverUrl.value)
}
const writeToken =() => {
WriteConfig("token", token.value)
}
const writeCheckDir = () => {
WriteConfig("check-dir", checkDir.value)
}
const writeConcurrentFiles = () => {
WriteConfig("handle-file-count", concurrentFiles.value)
}
const writeUploadThreads =() => {
WriteConfig("thread-count", uploadThreads.value)
}
const writeAutoStart = () => {
WriteConfig("is-run-on-start", autoStart.value)
}
// 加载配置
try {
GetConfig().then((config: Config) => {
@@ -109,25 +128,6 @@ try {
console.log(e)
}
watch(serverUrl, () => {
WriteConfig("url", serverUrl.value)
})
watch(token, () => {
WriteConfig("token", token.value)
})
watch(checkDir, () => {
WriteConfig("check-dir", checkDir.value)
})
watch(concurrentFiles, () => {
WriteConfig("handle-file-count", concurrentFiles.value)
})
watch(uploadThreads, () => {
WriteConfig("thread-count", uploadThreads.value)
})
watch(autoStart, () => {
WriteConfig("is-run-on-start", autoStart.value)
})
EventsOn("is-run", (run) => {
isRunning.value = run
})
@@ -144,34 +144,34 @@ EventsOn("log", (msg) => {
<div class="left-panel">
<div class="form-item">
<label>服务器地址</label>
<el-input v-model="serverUrl" placeholder="请输入服务器地址" :disabled="isRunning"/>
<el-input v-model="serverUrl" placeholder="请输入服务器地址" :disabled="isRunning" @change="writeServerUrl()"/>
</div>
<div class="form-item">
<label>Token</label>
<el-input v-model="token" placeholder="请输入Token" :disabled="isRunning"/>
<el-input v-model="token" placeholder="请输入Token" :disabled="isRunning" @change="writeToken()"/>
</div>
<div class="form-item">
<label>检测目录</label>
<div class="dir-input">
<el-input v-model="checkDir" placeholder="请选择检测目录" :disabled="isRunning"/>
<el-input v-model="checkDir" placeholder="请选择检测目录" :disabled="isRunning" @change="writeCheckDir()"/>
<el-button @click="selectDirectory" :disabled="isRunning">选择目录</el-button>
</div>
</div>
<div class="form-item">
<label>同时处理文件数</label>
<el-input-number v-model="concurrentFiles" :min="1" :max="100" :disabled="isRunning"/>
<el-input-number v-model="concurrentFiles" :min="1" :max="100" :disabled="isRunning" @change="writeConcurrentFiles()"/>
</div>
<div class="form-item">
<label>单文件上传线程</label>
<el-input-number v-model="uploadThreads" :min="1" :max="100" :disabled="isRunning"/>
<el-input-number v-model="uploadThreads" :min="1" :max="100" :disabled="isRunning" @change="writeUploadThreads()"/>
</div>
<div class="form-item">
<el-checkbox v-model="autoStart" label="运行时自动启动上传" size="large" :disabled="isRunning"/>
<el-checkbox v-model="autoStart" label="运行时自动启动上传" size="large" :disabled="isRunning" @change="writeAutoStart()"/>
</div>
<div class="form-item">
+33 -3
View File
@@ -3,6 +3,7 @@ package api
import (
"context"
"dypid-client/internal/config"
"fmt"
"io"
"net/http"
"net/url"
@@ -13,12 +14,39 @@ var httpClient = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 500,
MaxIdleConnsPerHost: 500,
IdleConnTimeout: 30 * time.Second,
IdleConnTimeout: 30 * time.Minute,
},
Timeout: 30 * time.Second,
}
var limit chan struct{}
func init() {
//限制同时请求数为500
limit = make(chan struct{}, 500)
}
// InitConn 创建连接池
func InitConn() {
for i := 0; i < 200; i++ {
resp, err := httpClient.Get(config.APPConfig.Url + "/api/test")
if err != nil {
fmt.Println(err)
return
}
defer func() {
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}()
}
}
func UploadDataToServer(ctx context.Context, data string) error {
limit <- struct{}{}
defer func() {
<-limit
}()
params := url.Values{}
params.Set("token", config.APPConfig.Token)
params.Set("data", data)
@@ -38,8 +66,10 @@ func UploadDataToServer(ctx context.Context, data string) error {
if err != nil {
return err
}
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
defer func() {
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}()
return err
}
+4
View File
@@ -2,6 +2,7 @@ package config
import (
"fmt"
"sync"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
@@ -17,6 +18,7 @@ type Config struct {
}
var APPConfig Config
var configMu sync.Mutex
const (
Url = "url"
@@ -70,6 +72,8 @@ func InitConfig() {
}
func WriteConfig(key string, value any) {
configMu.Lock()
viper.Set(key, value)
viper.WriteConfig()
configMu.Unlock()
}
+14 -4
View File
@@ -9,13 +9,14 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/wailsapp/wails/v2/pkg/runtime"
wailsruntime "github.com/wailsapp/wails/v2/pkg/runtime"
"golang.org/x/sync/errgroup"
)
@@ -42,6 +43,10 @@ func StartLooking(ctx context.Context, logChan *chan string, lookingPath string)
AddLog(logChan, `单文件上传线程: `+strconv.Itoa(config.APPConfig.ThreadCount))
AddLog(logChan, "===============================================")
AddLog(logChan, "正在创建连接池(连接池可避免首次大量上传时出现网络错误)")
api.InitConn()
AddLog(logChan, "创建连接池完成,开始运行程序")
progress.Clear()
//推送上传进度
go func() {
@@ -58,7 +63,7 @@ func StartLooking(ctx context.Context, logChan *chan string, lookingPath string)
pg = append(pg, p)
return true
})
runtime.EventsEmit(ctx, "progress", pg)
wailsruntime.EventsEmit(ctx, "progress", pg)
}
}
}()
@@ -217,6 +222,7 @@ func processFile(ctx context.Context, logChan *chan string, filePath string, fil
// 创建行通道
lines := make(chan string, 100)
defer close(lines)
var countLine int32 = 0
// 创建指定个worker同时处理文件上传
for i := 0; i < config.APPConfig.ThreadCount; i++ {
@@ -233,6 +239,12 @@ func processFile(ctx context.Context, logChan *chan string, filePath string, fil
// 读取文件并发送到通道
scanner := bufio.NewScanner(file)
go func() {
defer func() {
if r := recover(); r != nil {
_, f, l, _ := runtime.Caller(0)
fmt.Println("panic:", f+":"+strconv.Itoa(l), r)
}
}()
for scanner.Scan() {
select {
case <-ctx.Done():
@@ -246,7 +258,6 @@ func processFile(ctx context.Context, logChan *chan string, filePath string, fil
for int(countLine) != fileLines {
select {
case <-ctx.Done():
close(lines)
wg.Wait()
return
default:
@@ -259,7 +270,6 @@ func processFile(ctx context.Context, logChan *chan string, filePath string, fil
}
}
close(lines)
wg.Wait()
if err := scanner.Err(); err != nil {