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

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

  •  
  •   PeterYang1996 · 86 天前 · 3179 次点击
    这是一个创建于 86 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    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 条附言  ·  86 天前
    感谢各位,已解决
    38 条回复    2021-09-17 16:20:21 +08:00
    xgfan
        1
    xgfan   86 天前
    里面有个 for 循环啊。
    Jwyt
        2
    Jwyt   86 天前   ❤️ 11
    你是我见过现实中第一个把 main 打成 mian 的(
    pkoukk
        3
    pkoukk   86 天前
    for{}死循环啊
    hingbong
        4
    hingbong   86 天前
    他相当于用命令行重新启动了一次自己,然后就 return 了
    zjyl1994
        5
    zjyl1994   86 天前
    for 循环啊朋友
    for {

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

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

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

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