获取 “fork/exec /usr/bin/wc: 资源暂时不可用” 的错误信息。

huangapple go评论73阅读模式
英文:

Getting "fork/exec /usr/bin/wc: resource temporarily unavailable"

问题

我正在尝试使用golang执行netstat命令来查找正在使用的端口数量。

我正在使用以下代码:

func PortCheck() int {
    cmd := exec.Command("netstat", "-an")
    grep := exec.Command("grep", "8000")
    wc := exec.Command("wc", "-l")
    pipe, _ := cmd.StdoutPipe()
    defer pipe.Close()

    grep.Stdin = pipe
    pipe2, _ := grep.StdoutPipe()
    defer pipe2.Close()
    wc.Stdin = pipe2
    // 先运行ps命令。
    cmd.Start()
    grep.Start()
    out, err := wc.Output()
    if err != nil {
        // 如果有任何错误,打印出来。
        fmt.Println("无法运行命令:", err)
    }
    // 否则,打印运行命令的输出。
    fmt.Println("输出:", string(out))
    fmt.Println(cmd)

    ports, err := strconv.Atoi(strings.Split(string(out), "\n")[0])
    if err != nil {
        fmt.Println(err)
    }
    return ports
}

我正在并发地运行这个函数,假设运行10,000次。

它开始报错:

fork/exec /usr/bin/wc: 资源暂时不可用

请帮我解决这个问题,这个函数是否可以更优化,以找出正在使用的端口数量?

我希望能并发地运行给定的函数1百万次。

英文:

I am trying to execute a netstat command to find out number of ports in use using golang,

I am using the following code for that,

func PortCheck() int {
	cmd := exec.Command("netstat", "-an")
	grep := exec.Command("grep", "8000")
	wc := exec.Command("wc", "-l")
	pipe, _ := cmd.StdoutPipe()
	defer pipe.Close()

	grep.Stdin = pipe
	pipe2, _ := grep.StdoutPipe()
	defer pipe2.Close()
	wc.Stdin = pipe2
	// Run ps first.
	cmd.Start()
	grep.Start()
	out, err := wc.Output()
	if err != nil {
		// if there was any error, print it here
		fmt.Println("could not run command: ", err)
	}
	// otherwise, print the output from running the command
	fmt.Println("Output: ", string(out))
	fmt.Println(cmd)

	ports, err := strconv.Atoi(strings.Split(string(out), "\n")[0])
	if err != nil {
		fmt.Println(err)
	}
	return ports
}

I am running this function concurrently, let's say for 10,000 iterations,

it starts giving error:-

fork/exec /usr/bin/wc: resource temporarily unavailable

Please help me out with the solution,
Is this function will be more optimized, to find out the number of ports in use?

I am expecting to run the given function concurrently 1 million times.

答案1

得分: 4

你的实现没有等待进程退出。当达到最大用户进程数的ulimit时,程序无法fork新的进程。

PortCheck实现中,在返回之前,必须调用(*Cmd).Wait等待每个进程退出。

你还应该使用os.Pipe连接你的进程。这更或多或少是你的shell实现管道的方式。只使用(*Cmd).StdoutPipe从最后一个命令中读取结果。

如果你想提高性能:

  • 在Go中实现grep 8000 | wc -l。这样也可以减少错误。例如,我假设你不想匹配端口48000?或者你只想要TCP,而不是带有“8000”的UDP或Unix套接字?
  • ..或者完全用特定的Go实现替换netstat。例如,Linux的netstat读取和解释/proc/net/{tcp,tcp6,udp,...}。这些文件比netstat的输出更容易解析。它还避免了fork新进程和解析无关文件。这可能会快得多。它也不太可移植,但是OS的netstat实现之间可能存在细微差异,因此该函数可能仍然需要特定于OS的变体。
英文:

Your implementation is not waiting for the processes to exit. After the ulimit for max user proceses is reached the program is unable to fork new processes.

You must call (*Cmd).Wait to wait for every process to exit before returning from the PortCheck implementation.

You should also connect your processes using os.Pipe. This is more or less how your shell implements pipes. Only use (*Cmd).StdoutPipe to read the result from the final command.

If you want to improve performance:

  • Implement grep 8000 | wc -l in Go. This can also be less buggy. Eg, I assume you don't want to match port 48000? Or perhaps you only want TCP, instead of UDP or unix sockets with "8000" in the inode?
  • ..or replace netstat with a specific Go implementation entirely. Eg, Linux netstat reads and interprets /proc/net/{tcp,tcp6,udp,...}. These files are easier to parse than the netstat output. It also avoids forking new processes and parsing irrelevant files. This can be massively faster. It is also less portable, but there can be subtle differences between OS netstat implementations so this function may need OS specific variations anyway.

huangapple
  • 本文由 发表于 2023年1月4日 15:29:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75002167.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定