需要做一个服务在后台运行,又不想使用第三方进程管理工具,在网上找到一段代码,试了一下可以后台运行,不明白原理
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
Jwyt 2021-09-01 14:16:25 +08:00 11
你是我见过现实中第一个把 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 7
我的理解是这样的: 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 |