设为首页 收藏本站
查看: 719|回复: 0

[经验分享] Linux nohup实现PHP毫秒定时器

[复制链接]

尚未签到

发表于 2018-12-15 08:29:01 | 显示全部楼层 |阅读模式
  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重定向某个指定文件.
  ====================================
  #!/bin/bash
  PHP=/opt/php/bin/php
  CMD_DIR=/data/yii2-angularjs
  cd $CMD_DIR
  while :; do
  $PHP yii user/add-user
  echo "$PHP yii user/add-user"
  sleep 1
  done
  done
  done
  ====================================


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-651534-1-1.html 上篇帖子: memcached实现LNMP对php页面的缓存 下篇帖子: PHP知识大全【高级】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

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