zoukankan      html  css  js  c++  java
  • php守护进程,加linux命令nohup实现任务每秒执行一次

    简介:这是php守护进程,加linux命令nohup实现任务每秒执行一次的详细页面,介绍了和php,有关的知识、技巧、经验,和一些php源码等。

    class='pingjiaF' frameborder='0' src='http://biancheng.dnbcw.info/pingjia.php?id=340021' scrolling='no'>Unix中 nohup 命令功能就是不挂断地运行命令,同时 nohup 把程序的所有输出到放到当前目录 nohup.out 文件中,如果文件不可写,则放到 <用户主目录>/nohup.out 文件中。那么有了这个命令以后我们php就写成shell 脚本使用循环来让我们脚本一直运行下去,不管我们终端窗口是否关闭都能够让我们php 脚本一直运行下去。

    马上动手写个 PHP 小程序,功能为每30秒记录时间,写入到文件
    # vi for_ever.php
    #! /usr/local/php/bin/php
        define('ROOT', dirname(__FILE__).'/');
        set_time_limit(0);
        while (true) {
            file_put_contents(ROOT.'for_ever.txt', date('Y-m-d H:i:s')."\n", FILE_APPEND);
            echo date('Y-m-d H:i:s'), ' OK!';
            sleep(30);
        }
    ?>

    保存退出,然后赋予 for_ever.php 文件可执行权限:
    # chmod +x for_ever.php

    让它在再后台执行:
    # nohup /home/andy/for_ever.php.php &
    记得最后加上 & 符号,这样才能够跑到后台去运行

    执行上述命令后出现如下提示:
    [1] 5157
    nohup: appending output to 'nohup.out'

    所有命令执行输出信息都会放到 nohup.out 文件中
    这时你可以打开 for_ever.php 同目录下的 for_ever.txt 和 nohup.out 看看效果!

    好了,它会永远运行下去了,怎么结束它呢?
    # ps

        PID TTY TIME CMD
        4247 pts/1 00:00:00 bash
        5157 pts/1 00:00:00 for_ever.php
        5265 pts/1 00:00:00 ps

    # kill -9 5157
    找到进程号 5157 杀之,你将看到
    [1]+  Killed                  nohup /home/andy/for_ever.php

    OK!


    ====================


    在很多项目中,或许有很多类似的后端脚本需要通过crontab定时执行。比如每10秒检查一下用户状态。脚本如下:

    @file: /php_scripts/scan_userstatus.php

    #!/usr/bin/env php -q
    $status = has_goaway();
    if ($status) {
        //done
    }
    ?>


    通过crontab定时执行脚本scan_userstatus.php
    #echo “*:*/10 * * * * /php_scripts/scan_userstatus.php”

    这样,每隔10秒钟,就会执行该脚本。

    我们发现,在短时间内,该脚本的内存资源还没有释放完,又启用了新的脚本。也就是说:新脚本启动了,旧脚本占用的资源还没有如愿释放。如此,日积月累,浪费了很多内存资源。我们对这个脚本进行了一下改进,改进后如下:

    @file: /php_scripts/scan_userstatus.php

    #/usr/bin/env php -q
    while (1) {
        $status = has_goaway();
        if ($status) {
            //done
        }
        usleep(10000000);
    }
    ?>


    这样,不需要crontab了。可以通过以下命令执行脚本,达到相同的功能效果
    #chmod +x /php_scripts/scan_userstatus.php
    #nohup /php_scripts/scan_userstatus.php &
    在这里,我们通过&将脚本放到后台运行,为了防止随着终端会话窗口关闭进程被杀,我们使用了nohup命令。那么有没有办法,不使nohup命令,也能够运行呢,就像Unin/Linux Daemon一样。接下来,就是我们要讲的守护进程函数。

    什么是守护进程?一个守护进程通常补认为是一个不对终端进行控制的后台任务。它有三个很显著的特征:在后台运行,与启动他的进程脱离,无须控制终端。常用的实现方式是fork() -> setsid() -> fork() 详细如下:
    @file: /php_scripts/scan_userstatus.php

    #/usr/bin/env php -q
    daemonize();
    while (1) {
        $status = has_goaway();
        if ($status) {
            //done
        }
        usleep(10000000);
    }

    function daemonize() {
        $pid = pcntl_fork();
        if ($pid === -1 ) {
            return FALSE;
        } else if ($pid) {
            usleep(500);
            exit();                //exit parent
        }

        chdir("/");
        umask(0);
        $sid = posix_setsid();
        if (!$sid) {
            return FALSE;
        }

        $pid = pcntl_fork();
        if ($pid === -1) {
            return FALSE;
        } else if ($pid) {
            usleep(500);
            exit(0);
        }

        if (defined('STDIN')) {
            fclose(STDIN);
        }
        if (defined('STDOUT')){
            fclose(STDOUT);
        }
        if (defined('STDERR')) {
            fclose(STDERR);
        }
    }
    ?>


    实现了守护进程函数以后,则可以建立一个常驻进程,所以只需要执行一次:
    #/php_scripts/scan_userstatus.php

    这 里较为关键的二个php函数是pcntl_fork()和posix_setsid()。fork()一个进程,则表示创建了一个运行进程的副本,副本被 认为是子进程,而原始进程被认为是父进程。当fork()运行之后,则可以脱离启动他的进程与终端控制等,也意味着父进程可以自由退出。 pcntl_fork()返回值,-1表示执行失败,0表示在子进程中,而返进程ID号,则表示在父进程中。在这里,退出父进程。setsid(),它首 先使新进程成为一个新会话的“领导者”,最后使该进程不再控制终端,这也是成为守护进程最关键的一步,这意味着,不会随着终端关闭而强制退出进程。对于一 个不会被中断的常驻进程来说,这是很关键的一步。进行最后一次fork(),这一步不是必须的,但通常都这么做,它最大的意义是防止获得控制终端。(在直 接打开一个终端设备,而且没有使用O_NOCTTY标志的情况下, 会获得控制终端).

    其它事项说明:
    1) chdir() 将守护进程放到总是存在的目录中,另外一个好处是,你的常驻进程不会限制你umount一个文件系统。
    2)umask() 设置文件模式,创建掩码到最大的允许限度。如果一个守护进程需要创建具有可读,可写权限的文件,一个被继承的具有更严格权限的掩码会有反作用。
    3)fclose(STDIN), fclose(STDOUT), fclose(STDERR) 关闭标准I/O流。注意,如果有输出(echo),则守护进程会失败。所以通常将STDIN, STDOUT, STDERR重定向某个指定文件.

    爱J2EE关注Java迈克尔杰克逊视频站JSON在线工具

    http://biancheng.dnbcw.info/php/340021.html pageNo:7
  • 相关阅读:
    模板-树链剖分
    bzoj2523 聪明的学生
    P1220 关路灯
    BZOJ3572 [Hnoi2014]世界树
    BZOJ4013 [HNOI2015]实验比较
    BZOJ4012 [HNOI2015]开店
    BZOJ4011 [HNOI2015]落忆枫音
    BZOJ4009 [HNOI2015]接水果
    BZOJ4010 [HNOI2015]菜肴制作
    BZOJ4008 [HNOI2015]亚瑟王
  • 原文地址:https://www.cnblogs.com/ooooo/p/2245240.html
Copyright © 2011-2022 走看看