美文网首页
比调用Shell更高效的判断进程是否存在的方式

比调用Shell更高效的判断进程是否存在的方式

作者: ShootHzj | 来源:发表于2021-08-12 17:24 被阅读0次

有很多场景需要我们的代码检测一个进程是否存在,常用的一种方式是通过调用脚本通过ps -ef的方式查看,然而其实这种做法并不怎么高效,会fork一个进程出来,还会影响go协程的调度

一种更好的方式是可以通过解析/proc文件夹来得到想要的信息,其实可以通过strace命令查看,ps -ef也是读取了这个路径下的信息

image-20210812141644151

下面分别是java和go的轮子示例

使用正则表达式[0-9]+的原因是/proc路径下还有一些其他文件,其中pid都是数字。

java

private static final Pattern numberPattern = Pattern.compile("[0-9]+");

    public static boolean processExists(String processName) throws Exception {
        final File procFile = new File("/proc");
        if (!procFile.isDirectory()) {
            throw new Exception("why proc dir is not directory");
        }
        final File[] listFiles = procFile.listFiles();
        if (listFiles == null) {
            return false;
        }
        final List<File> procDir = Arrays.stream(listFiles).filter(f -> numberPattern.matcher(f.getName()).matches()).collect(Collectors.toList());
        // find the proc cmdline
        for (File file : procDir) {
            try {
                final byte[] byteArray = FileUtils.readFileToByteArray(new File(file.getCanonicalPath() + File.separator + "cmdline"));
                final byte[] bytes = new byte[byteArray.length];
                for (int i = 0; i < byteArray.length; i++) {
                    if (byteArray[i] != 0x00) {
                        bytes[i] = byteArray[i];
                    } else {
                        bytes[i] = (byte) 0x20;
                    }
                }
                final String cmdLine = new String(bytes, StandardCharsets.UTF_8);
                if (cmdLine.contains(processName)) {
                    return true;
                }
            } catch (IOException e) {
                // the proc may end during the loop, ignore it
                log.error("read file exception ", e);
            }
        }
        return false;
    }

go

func ProcessExists(processName string) (bool, error) {
    result := false
    fileInfos, err := ioutil.ReadDir("/proc")
    if err != nil {
        return false, err
    }
    for _, info := range fileInfos {
        name := info.Name()
        matched, err := regexp.MatchString("[0-9]+", name)
        if err != nil {
            return false, err
        }
        if !matched {
            continue
        }
        cmdLine, err := parseCmdLine("/proc/" + info.Name() + "/cmdline")
        if err != nil {
            glog.Error("read cmd line failed ", err)
            // the proc may end during the loop, ignore it
            continue
        }
        if strings.Contains(cmdLine, processName) {
            result = true
        }
    }
    return result, err
}

func parseCmdLine(path string) (string, error) {
    cmdData, err := ioutil.ReadFile(path)
    if err != nil {
        return "", err
    }
    if len(cmdData) < 1 {
        return "", nil
    }

    split := strings.Split(string(bytes.TrimRight(cmdData, string("\x00"))), string(byte(0)))
    return strings.Join(split, " "), nil
}

相关文章

网友评论

      本文标题:比调用Shell更高效的判断进程是否存在的方式

      本文链接:https://www.haomeiwen.com/subject/drwlbltx.html