简洁版本:
Golang 是否可以生成多个外部进程(shell 命令)在平行下,这样它就不会启动一个操作系统线程每个外部进程......并且在完成后仍然能够接收其输出?
更长的版本:
在 Elixir 中,如果使用端口,则可以生成数千个外部进程,而无需真正增加 Erlang 虚拟机中的线程数量。
例如。下面的代码片段,启动了2500个外部sleep
进程,仅由 20 个进程管理操作系统线程在 Erlang 虚拟机下:
defmodule Exmultiproc do
for _ <- 1..2500 do
cmd = "sleep 3600"
IO.puts "Starting another process ..."
Port.open({:spawn, cmd}, [:exit_status, :stderr_to_stdout])
end
System.cmd("sleep", ["3600"])
end
(前提是你设置了ulimit -n
到一个较高的数字,例如 10000)
另一方面,Go 中的以下代码应该做同样的事情 - 启动 2500 个外部sleep
进程 - 也启动 2500操作系统线程。所以它显然开始了一个操作系统线程每个(阻塞?)系统调用(以免阻塞整个CPU,或类似的,如果我理解正确的话):
package main
import (
"fmt"
"os/exec"
"sync"
)
func main() {
wg := new(sync.WaitGroup)
for i := 0; i < 2500; i++ {
wg.Add(1)
go func(i int) {
fmt.Println("Starting sleep ", i, "...")
cmd := exec.Command("sleep", "3600")
_, err := cmd.Output()
if err != nil {
panic(err)
}
fmt.Println("Finishing sleep ", i, "...")
wg.Done()
}(i)
}
fmt.Println("Waiting for WaitGroup ...")
wg.Wait()
fmt.Println("WaitGroup finished!")
}
因此,我想知道是否有一种方法可以编写 Go 代码,使其执行与 Elixir 代码类似的操作,而不是打开一个操作系统线程每个外部进程?
我基本上正在寻找一种方法来管理至少几千个外部长时间运行(最多 10 天)的进程,以一种尽可能减少操作系统中任何虚拟或物理限制的问题的方式。
(对于代码中的任何错误,我深表歉意,因为我是 Elixir 的新手,而且也是 Go 的新手。我渴望了解我所犯的任何错误。)
编辑:澄清了并行运行长时间运行的进程的要求。