设为首页收藏本站
开启辅助访问
切换到宽版

创星网络[分享知识 传递快乐]

 找回密码
 立即注册

QQ登录

只需一步,快速开始

用新浪微博登录

只需一步,快速搞定

搜索
查看: 3749|回复: 0
打印 上一主题 下一主题

PHP守护进程函数–后台执行脚本

[复制链接]

我玩的应用:

跳转到指定楼层
楼主
发表于 2012-9-21 22:01:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在很多项目中,或许有很多类似的后端脚本需要通过crontab定时执行。比如每10秒检查一下用户状态。脚本如下:
  1. @file: /php_scripts/scan_userstatus.php

  2. #!/usr/bin/env php -q
  3. <?php
  4. $status = has_goaway();
  5. if ($status) {
  6.     //done
  7. }
  8. ?>
复制代码
通过crontab定时执行脚本scan_userstatus.php
  1. #echo “*:*/10 * * * * /php_scripts/scan_userstatus.php”
复制代码
这样,每隔10秒钟,就会执行该脚本。

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


  2. #/usr/bin/env php -q
  3. <?php
  4. while (1) {
  5.     $status = has_goaway();
  6.     if ($status) {
  7.         //done
  8.     }
  9.     usleep(10000000);
  10. }
  11. ?>
复制代码
这样,不需要crontab了。可以通过以下命令执行脚本,达到相同的功能效果
  1. #chmod +x /php_scripts/scan_userstatus.php
  2. #nohup /php_scripts/scan_userstatus.php &
复制代码
在这里,我们通过&将脚本放到后台运行,为了防止随着终端会话窗口关闭进程被杀,我们使用了nohup命令。那么有没有办法,不使nohup命令,也能够运行呢,就像Unin/Linux Daemon一样。接下来,就是我们要讲的守护进程函数。

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


  2. #/usr/bin/env php -q
  3. <?php
  4. daemonize();
  5. while (1) {
  6.     $status = has_goaway();
  7.     if ($status) {
  8.         //done
  9.     }
  10.     usleep(10000000);
  11. }

  12. function daemonize() {
  13.     $pid = pcntl_fork();
  14.     if ($pid === -1 ) {
  15.         return FALSE;
  16.     } else if ($pid) {
  17.         usleep(500);
  18.         exit();                //exit parent
  19.     }

  20.     chdir("/");
  21.     umask(0);
  22.     $sid = posix_setsid();
  23.     if (!$sid) {
  24.         return FALSE;
  25.     }

  26.     $pid = pcntl_fork();
  27.     if ($pid === -1) {
  28.         return FALSE;
  29.     } else if ($pid) {
  30.         usleep(500);
  31.         exit(0);
  32.     }

  33.     if (defined('STDIN')) {
  34.         fclose(STDIN);
  35.     }
  36.     if (defined('STDOUT')){
  37.         fclose(STDOUT);
  38.     }
  39.     if (defined('STDERR')) {
  40.         fclose(STDERR);
  41.     }
  42. }
  43. ?>
复制代码
实现了守护进程函数以后,则可以建立一个常驻进程,所以只需要执行一次:
  1. #/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重定向某个指定文件.

延伸阅读:
1. Linux Daemon Write Howto
2. GearmanManager


from:http://www.perfgeeks.com/?p=105
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 转播转播 分享分享 分享淘帖
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|创星网络 ( 苏ICP备11027519号|网站地图  

GMT+8, 2024-9-22 06:46 , Processed in 0.086100 second(s), 26 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表