在Go中设置进程名称(如`ps`所示)
以下(正确)不起作用:
The following (rightfully) doesn't work:
package main
import (
"os"
"time"
)
func main() {
os.Args[0] = "custom name"
println("sleeping")
time.Sleep(1000 * time.Second)
println("done")
}
有些语言提供设置进程名称作为内置功能(在Ruby中,例如,它只是指定给 $ 0
)或作为第三方库( Python )。
Some languages provide this feature of setting process name as a built-in functionality (in Ruby, for instance, it is only a matter of assigning to $0
) or as a third-party library (Python).
我在寻找一个解决方案,至少在Linux上是有效的。
I'm looking for a solution that works, at least, on Linux.
有多种方法可以完成这,并且其中许多只在某些情况下工作。我不建议这样做,因为(有一点),它可能会导致您的流程在不同情况下显示不同的名称。他们需要使用系统调用和/或不安全,所以你故意颠覆Go语言的安全性。然而,这就是说,你的选择似乎是:
修改argv [0]
There are multiple ways to accomplish this, and many of them only work in certain situations. I don't really recommend doing it, as (for one thing) it can result in your process showing up with different names in different situations. They require using syscall and/or unsafe, and so you're deliberately subverting the safety of the Go language. That said, however, your options seem to be:
func SetProcessName(name string) error {
argv0str := (*reflect.StringHeader)(unsafe.Pointer(&os.Args[0]))
argv0 := (*[1 << 30]byte)(unsafe.Pointer(argv0str.Data))[:argv0str.Len]
n := copy(argv0, name)
if n < len(argv0) {
argv0[n] = 0
}
return nil
}
在Go中,您无权访问实际的argv数组本身(没有调用内部运行时函数),因此仅限于一个不超过长度的新名称当前进程名称。
In Go, you don't have access to the actual argv array itself (without calling internal runtime functions), so you are limited to a new name no longer than the length of the current process name.
这似乎主要适用于达尔文和Linux。
This seems to mostly work on both Darwin and Linux.
func SetProcessName(name string) error {
bytes := append([]byte(name), 0)
ptr := unsafe.Pointer(&bytes[0])
if _, _, errno := syscall.RawSyscall6(syscall.SYS_PRCTL, syscall.PR_SET_NAME, uintptr(ptr), 0, 0, 0, 0); errno != 0 {
return syscall.Errno(errno)
}
return nil
}
新名称最多可以为16个字节。
The new name can be at most 16 bytes.
这在达尔文不起作用,似乎并不在Linux上做了很多工作,虽然它成功了,PR_GET_NAME之后也报告了正确的名称。虽然这可能是我的Linux VM特有的。
This doesn't work on Darwin, and doesn't seem to do much on Linux, though it succeeds and PR_GET_NAME reports the correct name afterward. This may be something peculiar about my Linux VM, though.