首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >每个外部进程可以在不启动一个OS线程的情况下与外部进程进行派生和通信吗?

每个外部进程可以在不启动一个OS线程的情况下与外部进程进行派生和通信吗?
EN

Stack Overflow用户
提问于 2015-11-27 00:19:50
回答 1查看 3.7K关注 0票数 11

简写版:

在Golang中是否可以在并行的中生成许多外部进程(shell命令),这样它就不会在每个外部进程中启动一个操作系统线程.当它完成时还能接收到它的输出吗?

更长版本:

在Elixir中,如果使用端口,则可以生成数千个外部进程,而不必真正增加Erlang虚拟机中的线程数。

例如,下面的代码片段启动了2500个外部sleep进程,仅由Erlang下的20个操作系统线程管理:

代码语言:javascript
代码运行次数:0
运行
复制
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,或者类似的,如果我正确理解的话):

代码语言:javascript
代码运行次数:0
运行
复制
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天)的进程,在操作系统中任何虚拟或物理限制都会造成尽可能少的问题。

(对代码中的任何错误表示抱歉,因为我对“灵丹妙药”还不熟悉,而且还很新。我渴望了解我正在做的任何错误。)

编辑:澄清了并行运行长时间进程的要求.

EN

回答 1

Stack Overflow用户

发布于 2015-11-27 06:27:51

我发现如果我们没有wait进程,Go运行时将不会启动2500 operating system threads。因此,请使用cmd.Start()而不是cmd.Output()。

但是,如果不通过golang包使用操作系统线程,就不可能读取进程的stdout。我认为这是因为os包没有使用非阻塞io来读取管道。

下面的程序在我的Linux上运行良好,尽管它阻止了进程的stdout,正如@JimB在评论中所说的那样,也许是因为我们的输出很小,并且适合系统缓冲区。

代码语言:javascript
代码运行次数:0
运行
复制
func main() {
    concurrentProcessCount := 50
    wtChan := make(chan *result, concurrentProcessCount)
    for i := 0; i < concurrentProcessCount; i++ {
        go func(i int) {
            fmt.Println("Starting process ", i, "...")
            cmd := exec.Command("bash", "-c", "for i in 1 2 3 4 5; do echo to sleep $i seconds;sleep $i;echo done;done;")
            outPipe,_ := cmd.StdoutPipe()
            err := cmd.Start()
            if err != nil {
                panic(err)
            }
            <-time.Tick(time.Second)
            fmt.Println("Finishing process ", i, "...")
            wtChan <- &result{cmd.Process, outPipe}
        }(i)
    }

    fmt.Println("root:",os.Getpid());

    waitDone := 0
    forLoop:
    for{
        select{
        case r:=<-wtChan:
            r.p.Wait()
            waitDone++
            output := &bytes.Buffer{}
            io.Copy(output, r.b)
            fmt.Println(waitDone, output.String())
            if waitDone == concurrentProcessCount{
                break forLoop
            }
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33948726

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档