需要做一个服务在后台运行,又不想使用第三方进程管理工具,在网上找到一段代码,试了一下可以后台运行,不明白原理
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
![]() | 1 6IbA2bj5ip3tK49j 2021-09-01 14:14:19 +08:00 里面有个 for 循环啊。 |
![]() | 2 Dockerfile 2021-09-01 14:16:25 +08:00 ![]() 你是我见过现实中第一个把 main 打成 mian 的( |
![]() | 3 pkoukk 2021-09-01 14:16:55 +08:00 for{}死循环啊 |
4 hingbong 2021-09-01 14:20:33 +08:00 他相当于用命令行重新启动了一次自己,然后就 return 了 |
![]() | 5 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) } |
![]() | 6 indexphp 2021-09-01 14:22:34 +08:00 上面说 for 循环的,仔细看看在传入 `-d` 的时候真的有走到 for 循环? |
8 PeterYang1996 OP @hingbong 应该是这样 |
9 PeterYang1996 OP @indexphp 你别理他们了 |
10 opsll 2021-09-01 14:45:00 +08:00 ![]() 我的理解是这样的: cmd := exec.Command(args[0], arg...)这行代码,是将当前可执行文件,通过子进程的再启动一遍,后续执行 return 的时候主进程就退出了,而子进程就变成了孤儿进程,在后台执行。由于你这里有个 for 循环,那么就会在后台一直执行不退出。 |
![]() | 12 Akiya 2021-09-01 16:43:07 +08:00 这个就是 Daemonize 的标准做法啊,起一个子进程去跑,然后自己无了,那么就是在后台运行了。很多软件比如 nginx 实现就是这样的 |
![]() | 13 ysc3839 2021-09-01 16:55:38 +08:00 cmd := exec.Command(args[0], arg...) cmd.Env = os.Environ() cmd.Start() |
![]() | 14 ysc3839 2021-09-01 17:13:11 +08:00 @ysc3839 这么做有用的根本原因大概是 shell 只会等待子进程,不会等待子进程启动的孙进程,所以子进程启动一个新进程后自己退出,shell 就不会等待了。如果遇到了会等孙进程的 shell 或终端,这种做法就无效了。 |
17 darknoll 2021-09-01 21:41:11 +08:00 居然有好几个说 for 循环的。。。 |
![]() | 18 lululau 2021-09-01 22:33:18 +08:00 这个代码怎么说呢。。。知道 daemonize 这个词,竟然不知道 Google 一下 “How to make a daemon process in golang”,了解一下怎么正确编写 daemonize 代码 |
![]() | 19 wangsongyan 2021-09-01 22:45:04 +08:00 via iPhone @darknoll #17 没 for 循环能后台运行? |
20 JustLookBy 2021-09-01 23:08:43 +08:00 @wangsongyan 后台运行和 for 循环 有一毛钱关系,for 循环和 time.Sleep(一万年) 在这作用一样,都只是模拟长时间运行而已。。。 |
![]() | 21 wangsongyan 2021-09-02 06:54:14 +08:00 via iPhone @JustLookBy #20 你要这么说,我的回复少了两个字,没 for 循环能(一直)后台运行? |
![]() | 22 ihipop 2021-09-02 08:01:05 +08:00 via Android @wangsongyan 能,包括但不限于 sleep channel,等方法 |
24 darknoll 2021-09-02 09:05:38 +08:00 @wangsongyan 你到现在还没明白这段代码的要点? |
25 bing0 2021-09-02 09:39:14 +08:00 那么问题来了,僵尸进程会内存溢出吗? |
26 lolizeppelin 2021-09-02 11:34:15 +08:00 找资料学把 fork setsid setuid setgid 和信号 搞清楚,别走 cmd 这种邪门歪道 实在不想学你还可以直接用 systemd 来管 但是无论怎么搞 标准做法还是要处理信号来方便退出 |
![]() | 27 cenbiq 2021-09-02 12:31:34 +08:00 不太理解前面说的孤儿进程,我直接启动进程就执行 for 不能做到吗?一定要启动子进程再让自身 return 才行? |
![]() | 28 koolob 2021-09-02 12:52:16 +08:00 @cenbiq #27 直接启动然后 for 的话,此时控制台退出,程序就中断了。后台运行的目的是实现在控制台启动程序后,控制台退出,程序依然运行。 |
![]() | 29 koolob 2021-09-02 12:54:51 +08:00 用这种做法还需要配套方案才行,比如保存进程号,处理各种信号,这样才能算是稳定的程序。只是本地练习的话倒是无所谓。 |
30 mxT52CRuqR6o5 2021-09-02 15:22:43 +08:00 问:水为什么会往低处流? 答:因为低处的位置比高处低。 |
31 mxT52CRuqR6o5 2021-09-02 15:29:40 +08:00 @cenbiq “后台”运行 |
32 barathrum 2021-09-02 16:07:35 +08:00 就是 double fork |
![]() | 33 ragnaroks 2021-09-02 22:42:10 +08:00 看到上面几个 for 循环我一下以为我从小学开始学的 C 路走歪了,一般都是起个线程,主线程等待子线程结束,最简单的实现 |
![]() | 34 lasuar 2021-09-03 11:08:36 +08:00 套娃,多此一举。 ./main & |
35 jianjian714 2021-09-03 14:50:31 +08:00 go 热重启算后台运行的一个完善的应用了吧 |
![]() | 36 necodba 2021-09-16 19:04:34 +08:00 article-spider 里面能不能加一个并发。或者限定每一条获取数据的时间频率,另外如果首页的地址是 /article/1 , 第二页地址是 /pages?=2&type=commic&article=11,这种翻页完全改了参数的咋整 |
37 PeterYang1996 OP @necodba 你的 issue 这么提到这里了。。 |
38 PeterYang1996 OP |