将-程序性能为后盾进程或守护进程-适用指南-Go (程序性能的要素有哪些?)
本文讨论了如何经过Go代码实如今后盾运转的程序。最近我用Go言语开发了一个WebSocket服务,我宿愿它能在后盾运转,并在异常分开时智能从新启动。我的全体思绪是将程序转为后盾进程,也就是守护进程(daemon)。它不处置详细的业务逻辑,而是再次经常使用相反的参数调用自身,启动一个子进程来处置业务逻辑。守护进程监督子进程的形态,假设子进程分开,则再次启动一个新的子进程。这样就能保障在服务异常中断时及时重启。
我在网上找到了一个开源库,.com/sevlyar/go-daemon,它很繁难地成功了在后盾启动一个新的进程,但假设后盾进程再次尝试作为另一个后盾进程启动,会出现失误。
起初我浏览了源代码才发现:为了辨别当行进程是父进程还是子进程,作者奇妙地设计了一个环境变量标识。正是由于这种识别战略,该库只能启动一次性自身作为后盾进程,无法延续启动自身为后盾进程。
不过,这种经常使用环境变量来辨别进程身份的思绪给我启示很大。基于这个想法,我经过加长和优化,最终成功了在坚持参数不变的状况下延续启动自身为后盾进程。我对作者示意敬意。
此外,我还找到了一些其余的库,它们的思绪有所不同,重要经过减少不凡参数来标志进程身份。然而,这些方法并没有完美地处置让进程启动自身的疑问,令我有些遗憾。
最终,我选择自己成功一个库来处置我的名目需求,并宿愿它是一个通用的库,可以极速繁难地将用Go言语编写的服务程序转为后盾运转或守护进程形式运转。本文总结了我在这次探求中的阅历和收获。
首先,让咱们辨别一下两个概念:后盾运转和守护进程。平时交换时,咱们或许不太辨别或辨别不够明晰。在本文中,我想明白如下定义:
后盾运转:指进程在操作系统中以非显示形式运转,没有与任何命令行终端或程序界面关系联。这种形式下运转的进程称为后盾进程,比如没有与任何终端关系联的命令行程序进程。
守护进程:也称为守护进程,它首先以后台运转形式启动,而后还有额外的职责。在本文中,我的定义是守护进程可以监督Go服务程序进程的形态,假设异常分开,可以智能从新启动。这样守护进程可以确保服务程序不时在后盾运转,即使它在某些状况下解体或异常中断。
接上去,我将引见如何经常使用Go代码来实如今后盾运转的程序,并将其转化为一个守护进程。
后盾运转程序
要将Go程序在后盾运转,可以经常使用一些操作系统级别的方法。以下是一种繁难的方法:
packagemnimport("fmt""os""os/exec""syscall")funcmain(){ifos.Getppid()!=1{cmd:=exec.Command(os.Args[0])cmd.Start()fmt.Println("BackgroundprocessID:",cmd.Process.Pid)os.Exit(0)}//在这里写入详细的业务逻辑代码fmt.Println("Runninginbackground...")select{}}
在下面的代码中,咱们首先经常使用os.Getppid()函数失掉当行进程的父进程ID。假设父进程不是1,说明当行进程不是守护进程,而是从终端启动的。在这种状况下,咱们创立一个新的命令,经常使用相反的参数再次启动程序,并在后盾运转。咱们打印出新进程的PID,并分开初始进程。
假设进程的父进程是1,那么说明当行进程曾经是守护进程了,咱们可以在此处写入详细的业务逻辑代码。
经常使用这种方法,咱们可以确保程序在后盾运转,而且还可以审核能否曾经启动了一个后盾进程。
守护进程
将程序转化为守护进程须要额外的步骤,咱们须要创立一个监听子进程形态的循环,并在子进程异常分开时从新启动它。以下是一个繁难的守护进程成功:
packagemainimport("fmt""os""os/exec""syscall")funcmain(){ifos.Getppid()!=1{cmd:=exec.Command(os.Args[0])cmd.Start()fmt.Println("BackgroundprocessID:",cmd.Process.Pid)os.Exit(0)}//在这里写入详细的业务逻辑代码fmt.Println("Runninginbackground...")for{cmd:=exec.Command(os.Args[0])cmd.Start()exitCh:=make(chanerror)gofunc(){exitCh<-cmd.Wait()}()err:=<-exitChiferr!=nil{fmt.Println("Processexitedwitherror:",err)}else{fmt.Println("Processexitedsuccessfully")}select{case<-exitCh:default:}}}
在下面的代码中,咱们减少了一个循环,用于监听子进程的形态。在每次子进程分开之后,咱们经常使用相反的参数再次启动守护进程,并从新开局监听。这样就可以确保服务程序在异常分开时能够智能从新启动。
这只是一个繁难的守护进程成功,你可以依据自己的需求启动裁减和优化。
linux内核如何对进程分类
可以吧,linux内核的三种调度方法:1,SCHED_OTHER 分时调度策略,2,SCHED_FIFO实时调度策略,先到先服务3,SCHED_RR实时调度策略,时间片轮转实时进程将得到优先调用,实时进程根据实时优先级决定调度权值,分时进程则通过nice和counter值决定权值,nice越小,counter越大,被调度的概率越大,也就是曾经使用了cpu最少的进程将会得到优先调度。 SHCED_RR和SCHED_FIFO的不同:当采用SHCED_RR策略的进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。 放在队列尾保证了所有具有相同优先级的RR任务的调度公平。 SCHED_FIFO一旦占用cpu则一直运行。 一直运行直到有更高优先级任务到达或自己放弃。 如果有相同优先级的实时进程(根据优先级计算的调度权值是一样的)已经准备好,FIFO时必须等待该进程主动放弃后才可以运行这个优先级相同的任务。 而RR可以让每个任务都执行一段时间。 相同点:RR和FIFO都只用于实时任务。 创建时优先级大于0(1-99)。 按照可抢占优先级调度算法进行。 就绪态的实时任务立即抢占非实时任务。 请参考
我怎样使我的程序作为守护程序运行?
许多系统服务由守护程序实施;如网络服务,打印等。 简单地在后台启动一个程序并非足够是这些长时间运行的程序;那种方法没有正确地将进程从启动它的终端脱离(detach)。 而且,启动守护程序的普遍接受的的方法是简单地手工执行或从rc脚本程序执行(译者注:rc:runcom);并希望这个守护程序将其*自身*安置到后台。 这里是成为守护程序的步骤: 调用‘fork()’以便父进程可以退出,这样就将控制权归还给运行你程序的 命令行或shell程序。 需要这一步以便保证新进程不是一个进程组头领进程(process group leader)。 下一步,‘setsid()’,会因为你是进程组头领进程而失败。 调用‘setsid()’ 以便成为一个进程组和会话组的头领进程。 由于一个控制终端 与一个会话相关联,而且这个新会话还没有获得一个控制终端,我们的进程没 有控制终端,这对于守护程序来说是一件好事。 再次调用‘fork()’所以父进程(会话组头领进程)可以退出。 这意味着我们,一 个非会话组头领进程永远不能重新获得控制终端。 调用‘chdir(/)’确认我们的进程不保持任何目录于使用状态。 不做这个会导 致系统管理员不能卸装(umount)一个文件系统,因为它是我们的当前工作目录。 [类似的,我们可以改变当前目录至对于守护程序运行重要的文件所在目录] 调用‘umask(0)’以便我们拥有对于我们写的任何东西的完全控制。 我们不知 道我们继承了什么样的umask。 [这一步是可选的](译者注:这里指步骤5,因为守护程序不一定需要写文件) 调用‘close()’关闭文件描述符0,1和2。 这样我们释放了从父进程继承的标 准输入,标准输出,和标准错误输出。 我们没办法知道这些文描述符符可能 已经被重定向去哪里。 注意到许多守护程序使用‘sysconf()’来确认 ‘_SC_OPEN_MAX’的限制。 ‘_SC_OPEN_MAX’告诉你每个进程能够打 开的最多文件数。 然后使用一个循环,守护程序可以关闭所有可能的文件描 述符。 你必须决定你需要做这个或不做。 如果你认为有可能有打开的文件描 述符,你需要关闭它们,因为系统有一个同时打开文件数的限制。 为标准输入,标准输出和标准错误输出建立新的文件描述符。 即使你不打算 使用它们,打开着它们不失为一个好主意。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。