V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
PeterYang1996
V2EX  ›  程序员

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

  •  
  •   PeterYang1996 · 2021-09-01 14:11:09 +08:00 · 4305 次点击
    这是一个创建于 1178 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    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 条附言  ·  2021-09-01 17:09:38 +08:00
    感谢各位,已解决
    38 条回复    2021-09-17 16:20:21 +08:00
    6IbA2bj5ip3tK49j
        1
    6IbA2bj5ip3tK49j  
       2021-09-01 14:14:19 +08:00
    里面有个 for 循环啊。
    Jwyt
        2
    Jwyt  
       2021-09-01 14:16:25 +08:00   ❤️ 11
    你是我见过现实中第一个把 main 打成 mian 的(
    pkoukk
        3
    pkoukk  
       2021-09-01 14:16:55 +08:00
    for{}死循环啊
    hingbong
        4
    hingbong  
       2021-09-01 14:20:33 +08:00
    他相当于用命令行重新启动了一次自己,然后就 return 了
    zjyl1994
        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)
    }
    indexphp
        6
    indexphp  
       2021-09-01 14:22:34 +08:00
    上面说 for 循环的,仔细看看在传入 `-d` 的时候真的有走到 for 循环?
    indexphp
        7
    indexphp  
       2021-09-01 14:24:12 +08:00
    @hingbong 我理解有误,这个是正解,自己启动了一下自己。
    PeterYang1996
        8
    PeterYang1996  
    OP
       2021-09-01 14:24:39 +08:00
    @hingbong 应该是这样
    PeterYang1996
        9
    PeterYang1996  
    OP
       2021-09-01 14:26:38 +08:00
    @indexphp 你别理他们了
    opsll
        10
    opsll  
       2021-09-01 14:45:00 +08:00   ❤️ 7
    我的理解是这样的: cmd := exec.Command(args[0], arg...)这行代码,是将当前可执行文件,通过子进程的再启动一遍,后续执行 return 的时候主进程就退出了,而子进程就变成了孤儿进程,在后台执行。由于你这里有个 for 循环,那么就会在后台一直执行不退出。
    wunonglin
        11
    wunonglin  
       2021-09-01 14:51:07 +08:00
    @opsll #10 孤儿进程哈哈哈哈哈哈哈哈哈哈
    Akiya
        12
    Akiya  
       2021-09-01 16:43:07 +08:00
    这个就是 Daemonize 的标准做法啊,起一个子进程去跑,然后自己无了,那么就是在后台运行了。很多软件比如 nginx 实现就是这样的
    ysc3839
        13
    ysc3839  
       2021-09-01 16:55:38 +08:00
    cmd := exec.Command(args[0], arg...)
    cmd.Env = os.Environ()
    cmd.Start()

    就是再次启动了自身。
    ysc3839
        14
    ysc3839  
       2021-09-01 17:13:11 +08:00
    @ysc3839 这么做有用的根本原因大概是 shell 只会等待子进程,不会等待子进程启动的孙进程,所以子进程启动一个新进程后自己退出,shell 就不会等待了。如果遇到了会等孙进程的 shell 或终端,这种做法就无效了。
    ihipop
        15
    ihipop  
       2021-09-01 21:00:38 +08:00 via Android
    @ysc3839 而且这样会导致如果这个孙进程没人回收变僵尸。
    Senorsen
        16
    Senorsen  
       2021-09-01 21:13:41 +08:00
    @wunonglin orphan process 就是叫孤儿进程(虽然一翻译成中文确实有点违和感)
    darknoll
        17
    darknoll  
       2021-09-01 21:41:11 +08:00
    居然有好几个说 for 循环的。。。
    lululau
        18
    lululau  
       2021-09-01 22:33:18 +08:00
    这个代码怎么说呢。。。知道 daemonize 这个词,竟然不知道 Google 一下 “How to make a daemon process in golang”,了解一下怎么正确编写 daemonize 代码
    wangsongyan
        19
    wangsongyan  
       2021-09-01 22:45:04 +08:00 via iPhone
    @darknoll #17 没 for 循环能后台运行?
    JustLookBy
        20
    JustLookBy  
       2021-09-01 23:08:43 +08:00
    @wangsongyan 后台运行和 for 循环 有一毛钱关系,for 循环和 time.Sleep(一万年) 在这作用一样,都只是模拟长时间运行而已。。。
    wangsongyan
        21
    wangsongyan  
       2021-09-02 06:54:14 +08:00 via iPhone
    @JustLookBy #20 你要这么说,我的回复少了两个字,没 for 循环能(一直)后台运行?
    ihipop
        22
    ihipop  
       2021-09-02 08:01:05 +08:00 via Android
    @wangsongyan 能,包括但不限于 sleep channel,等方法
    itfanr
        23
    itfanr  
       2021-09-02 08:45:47 +08:00
    @opsll 其实就是 linux fork 那一套
    darknoll
        24
    darknoll  
       2021-09-02 09:05:38 +08:00
    @wangsongyan 你到现在还没明白这段代码的要点?
    bing0
        25
    bing0  
       2021-09-02 09:39:14 +08:00
    那么问题来了,僵尸进程会内存溢出吗?
    lolizeppelin
        26
    lolizeppelin  
       2021-09-02 11:34:15 +08:00
    找资料学把 fork setsid setuid setgid 和信号 搞清楚,别走 cmd 这种邪门歪道

    实在不想学你还可以直接用 systemd 来管 但是无论怎么搞 标准做法还是要处理信号来方便退出
    cenbiq
        27
    cenbiq  
       2021-09-02 12:31:34 +08:00
    不太理解前面说的孤儿进程,我直接启动进程就执行 for 不能做到吗?一定要启动子进程再让自身 return 才行?
    koolob
        28
    koolob  
       2021-09-02 12:52:16 +08:00
    @cenbiq #27 直接启动然后 for 的话,此时控制台退出,程序就中断了。后台运行的目的是实现在控制台启动程序后,控制台退出,程序依然运行。
    koolob
        29
    koolob  
       2021-09-02 12:54:51 +08:00
    用这种做法还需要配套方案才行,比如保存进程号,处理各种信号,这样才能算是稳定的程序。只是本地练习的话倒是无所谓。
    mxT52CRuqR6o5
        30
    mxT52CRuqR6o5  
       2021-09-02 15:22:43 +08:00
    问:水为什么会往低处流?
    答:因为低处的位置比高处低。
    mxT52CRuqR6o5
        31
    mxT52CRuqR6o5  
       2021-09-02 15:29:40 +08:00
    @cenbiq “后台”运行
    barathrum
        32
    barathrum  
       2021-09-02 16:07:35 +08:00
    就是 double fork
    ragnaroks
        33
    ragnaroks  
       2021-09-02 22:42:10 +08:00
    看到上面几个 for 循环我一下以为我从小学开始学的 C 路走歪了,一般都是起个线程,主线程等待子线程结束,最简单的实现
    lasuar
        34
    lasuar  
       2021-09-03 11:08:36 +08:00
    套娃,多此一举。 ./main &
    jianjian714
        35
    jianjian714  
       2021-09-03 14:50:31 +08:00
    go 热重启算后台运行的一个完善的应用了吧
    necodba
        36
    necodba  
       2021-09-16 19:04:34 +08:00
    article-spider 里面能不能加一个并发。或者限定每一条获取数据的时间频率,另外如果首页的地址是 /article/1 , 第二页地址是 /pages?=2&type=commic&article=11,这种翻页完全改了参数的咋整
    PeterYang1996
        37
    PeterYang1996  
    OP
       2021-09-17 16:18:53 +08:00
    @necodba 你的 issue 这么提到这里了。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2765 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 13:33 · PVG 21:33 · LAX 05:33 · JFK 08:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.