各位大佬,帮忙看一下这段代码是什么原理让 go 保持后台运行的

2021-09-01 14:11:09 +08:00
 PeterYang1996

需要做一个服务在后台运行,又不想使用第三方进程管理工具,在网上找到一段代码,试了一下可以后台运行,不明白原理

package main

import (
	"log"
	"os"
	"os/exec"
	"strconv"
	"time"
)

func main() {
	args := os.Args
	daemon := false
	for k, v := range args {
		if v == "-d" {
			daemon = true
			args[k] = ""
		}
	}

	if daemon {
		Daemonize(args...)
		return
	}

	file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_RDWR, 0664)

	if err != nil {

		log.Println(err)

		return
	}

	defer file.Close()
	for {

		file.Write([]byte(strconv.Itoa((int)(time.Now().Unix())) + "\n"))

		time.Sleep(time.Second * 1)
	}
}

func Daemonize(args ...string) {
	var arg []string
	if len(args) > 1 {
		arg = args[1:]
	}
	cmd := exec.Command(args[0], arg...)
	cmd.Env = os.Environ()
	cmd.Start()
}

后台运行 ./mian -d

4061 次点击
所在节点    程序员
38 条回复
xgfan
2021-09-01 14:14:19 +08:00
里面有个 for 循环啊。
Jwyt
2021-09-01 14:16:25 +08:00
你是我见过现实中第一个把 main 打成 mian 的(
pkoukk
2021-09-01 14:16:55 +08:00
for{}死循环啊
hingbong
2021-09-01 14:20:33 +08:00
他相当于用命令行重新启动了一次自己,然后就 return 了
zjyl1994
2021-09-01 14:22:30 +08:00
for 循环啊朋友
for {

file.Write([]byte(strconv.Itoa((int)(time.Now().Unix())) + "\n"))

time.Sleep(time.Second * 1)
}
indexphp
2021-09-01 14:22:34 +08:00
上面说 for 循环的,仔细看看在传入 `-d` 的时候真的有走到 for 循环?
indexphp
2021-09-01 14:24:12 +08:00
@hingbong 我理解有误,这个是正解,自己启动了一下自己。
PeterYang1996
2021-09-01 14:24:39 +08:00
@hingbong 应该是这样
PeterYang1996
2021-09-01 14:26:38 +08:00
@indexphp 你别理他们了
opsll
2021-09-01 14:45:00 +08:00
我的理解是这样的: cmd := exec.Command(args[0], arg...)这行代码,是将当前可执行文件,通过子进程的再启动一遍,后续执行 return 的时候主进程就退出了,而子进程就变成了孤儿进程,在后台执行。由于你这里有个 for 循环,那么就会在后台一直执行不退出。
wunonglin
2021-09-01 14:51:07 +08:00
@opsll #10 孤儿进程哈哈哈哈哈哈哈哈哈哈
Akiya
2021-09-01 16:43:07 +08:00
这个就是 Daemonize 的标准做法啊,起一个子进程去跑,然后自己无了,那么就是在后台运行了。很多软件比如 nginx 实现就是这样的
ysc3839
2021-09-01 16:55:38 +08:00
cmd := exec.Command(args[0], arg...)
cmd.Env = os.Environ()
cmd.Start()

就是再次启动了自身。
ysc3839
2021-09-01 17:13:11 +08:00
@ysc3839 这么做有用的根本原因大概是 shell 只会等待子进程,不会等待子进程启动的孙进程,所以子进程启动一个新进程后自己退出,shell 就不会等待了。如果遇到了会等孙进程的 shell 或终端,这种做法就无效了。
ihipop
2021-09-01 21:00:38 +08:00
@ysc3839 而且这样会导致如果这个孙进程没人回收变僵尸。
Senorsen
2021-09-01 21:13:41 +08:00
@wunonglin orphan process 就是叫孤儿进程(虽然一翻译成中文确实有点违和感)
darknoll
2021-09-01 21:41:11 +08:00
居然有好几个说 for 循环的。。。
lululau
2021-09-01 22:33:18 +08:00
这个代码怎么说呢。。。知道 daemonize 这个词,竟然不知道 Google 一下 “How to make a daemon process in golang”,了解一下怎么正确编写 daemonize 代码
wangsongyan
2021-09-01 22:45:04 +08:00
@darknoll #17 没 for 循环能后台运行?
JustLookBy
2021-09-01 23:08:43 +08:00
@wangsongyan 后台运行和 for 循环 有一毛钱关系,for 循环和 time.Sleep(一万年) 在这作用一样,都只是模拟长时间运行而已。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/799257

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX