Golang插件编译时间过长问题探讨
Golang插件编译时间过长问题探讨 我在我的项目中使用了Golang的插件概念。(go build -buildmode=plugin) 将一个插件编译成.so文件平均需要15秒。 如果我想要编译三到四个插件,这几乎需要45秒。 有没有办法减少编译到.so文件的时间? 或者 有没有其他方法可以更快地编译? 或者 至少可以减少多个插件的编译时间(例如,我能否并行运行所有插件,使得总空闲时间始终是15秒)
这是我在一个循环中使用的命令,该命令遍历一个列表并执行相同的命令:
go build -buildmode=plugin -o "classes/"+List[i]+".so "+ "classes/" + List[i].action + ".go"
更多关于Golang插件编译时间过长问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我正在借助一个Node.js进程来执行这个shell命令。
更多关于Golang插件编译时间过长问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你是如何在循环中运行那个命令的?是在 shell 脚本里,还是其他方式?
感谢您的建议。 Nodejs 是异步代码执行,因此这个循环几乎同时开始,也就是说,命令几乎是同时运行的。
我不熟悉Node,但我建议你寻找一种方法从那里并行启动命令。如果你是从Go本身运行编译,我可以帮助你,但就像我说的,我不了解Node。
对于Golang插件编译时间过长的问题,可以通过并行编译来显著减少总时间。以下是几种实现方式:
1. 使用Golang并发编译插件
package main
import (
"fmt"
"os/exec"
"sync"
)
func compilePlugin(pluginName, actionFile string, wg *sync.WaitGroup) {
defer wg.Done()
cmd := exec.Command("go", "build",
"-buildmode=plugin",
"-o", fmt.Sprintf("classes/%s.so", pluginName),
fmt.Sprintf("classes/%s.go", actionFile))
if err := cmd.Run(); err != nil {
fmt.Printf("编译插件 %s 失败: %v\n", pluginName, err)
} else {
fmt.Printf("插件 %s 编译完成\n", pluginName)
}
}
func main() {
plugins := []struct {
name string
action string
}{
{"plugin1", "action1"},
{"plugin2", "action2"},
{"plugin3", "action3"},
}
var wg sync.WaitGroup
for _, p := range plugins {
wg.Add(1)
go compilePlugin(p.name, p.action, &wg)
}
wg.Wait()
fmt.Println("所有插件编译完成")
}
2. 使用Goroutine池控制并发数
package main
import (
"fmt"
"os/exec"
"sync"
)
func worker(id int, jobs <-chan string, results chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
for plugin := range jobs {
cmd := exec.Command("go", "build",
"-buildmode=plugin",
"-o", fmt.Sprintf("classes/%s.so", plugin),
fmt.Sprintf("classes/%s.go", plugin))
if err := cmd.Run(); err != nil {
results <- fmt.Sprintf("Worker %d: 插件 %s 编译失败", id, plugin)
} else {
results <- fmt.Sprintf("Worker %d: 插件 %s 编译成功", id, plugin)
}
}
}
func main() {
plugins := []string{"plugin1", "plugin2", "plugin3", "plugin4"}
numWorkers := 4
jobs := make(chan string, len(plugins))
results := make(chan string, len(plugins))
var wg sync.WaitGroup
// 启动worker
for w := 1; w <= numWorkers; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// 发送任务
for _, plugin := range plugins {
jobs <- plugin
}
close(jobs)
// 收集结果
go func() {
wg.Wait()
close(results)
}()
// 输出结果
for result := range results {
fmt.Println(result)
}
}
3. 使用sync.ErrGroup(需要golang.org/x/sync)
package main
import (
"context"
"fmt"
"os/exec"
"golang.org/x/sync/errgroup"
)
func compilePlugin(ctx context.Context, pluginName string) error {
cmd := exec.CommandContext(ctx, "go", "build",
"-buildmode=plugin",
"-o", fmt.Sprintf("classes/%s.so", pluginName),
fmt.Sprintf("classes/%s.go", pluginName))
return cmd.Run()
}
func main() {
plugins := []string{"plugin1", "plugin2", "plugin3"}
g, ctx := errgroup.WithContext(context.Background())
for _, plugin := range plugins {
plugin := plugin // 创建局部变量副本
g.Go(func() error {
fmt.Printf("开始编译插件: %s\n", plugin)
err := compilePlugin(ctx, plugin)
if err != nil {
return fmt.Errorf("编译插件 %s 失败: %w", plugin, err)
}
fmt.Printf("插件 %s 编译完成\n", plugin)
return nil
})
}
if err := g.Wait(); err != nil {
fmt.Printf("编译过程中出错: %v\n", err)
} else {
fmt.Println("所有插件编译成功")
}
}
4. Shell脚本并行编译
#!/bin/bash
# 并行编译所有插件
compile_plugin() {
local plugin=$1
echo "开始编译: $plugin"
go build -buildmode=plugin -o "classes/${plugin}.so" "classes/${plugin}.go"
echo "完成编译: $plugin"
}
# 导出函数以便在子进程中使用
export -f compile_plugin
# 插件列表
plugins=("plugin1" "plugin2" "plugin3" "plugin4")
# 使用xargs并行执行
printf "%s\n" "${plugins[@]}" | xargs -P 4 -I {} bash -c 'compile_plugin "$@"' _ {}
echo "所有插件编译完成"
5. 使用Makefile并行编译
.PHONY: all plugins clean
PLUGINS := plugin1 plugin2 plugin3 plugin4
SO_FILES := $(addprefix classes/,$(addsuffix .so,$(PLUGINS)))
all: plugins
classes/%.so: classes/%.go
@echo "编译插件: $*"
@go build -buildmode=plugin -o $@ $<
plugins: $(SO_FILES)
# 并行编译(使用make -j选项)
# 运行: make -j4 plugins
clean:
rm -f classes/*.so
使用并行编译后,4个插件的编译时间可以从60秒减少到约15秒(假设有足够的CPU核心)。编译时可以通过设置GOMAXPROCS环境变量或使用-j选项(在Makefile中)来控制并发数。

