使用PHP作为守护进程是明智的吗?

我希望创build一个后台进程,而且我被告知这些进程通常用C语言或者类似的东西写成。 我最近发现PHP可以用来创build一个守护进程,我希望得到一些build议,如果我应该这样使用PHP。

这是我的守护进程的要求。

  • 连续检查一行是否已经添加到MySQL数据库表中
  • 对从数据库检索的内容运行FFmpeg命令
  • 将输出插入到MySQL表中

我不确定我还能提供什么帮助做出这个决定。 只是补充一点,我以前没有做过C。 只有Java和PHP和基本的bash脚本。

它甚至会使性能差异如此之大?

请允许我的无知,我正在学习! 🙂

谢谢大家

Solutions Collecting From Web of "使用PHP作为守护进程是明智的吗?"

正如其他人已经指出,各种版本的PHP有垃圾收集器的问题。 当然,如果你知道你的版本没有这个问题,你可以消除这个问题。 关键是,你知道(当然),直到你写守护进程,并通过valgrind运行,看看安装的PHP泄漏或没有在任何给定的机器上。 所以在这方面,你可能只是为了发现Zend认为是固定的,可能仍然是错误的,或者你正在处理稍微老一些的PHP或者一些扩展。 恶心。

另一个问题是一些有问题的信号。 根据我的经验,信号处理程序并不总是用PHP正确输入,特别是当信号排队而不是合并时。 这可能不是你的问题,即如果你只需要处理SIGINT / SIGUSR1 / SIGUSR2 / SIGHUP。

所以我建议:

如果守护进程很简单,请继续使用PHP。 如果看起来会变得相当复杂,或者分配大量内存,那么可以考虑在使用PHP进行原型设计之后用C语言编写它。

我是一个相当死硬的C人。 但是,我发现使用PHP快速提取某些东西没什么问题(超出了我解释的情况)。 我也没有看到使用PHP来创建可能或可能不会在C中重写的原型的任何错误。例如,处理数据库的东西将会更简单,如果您使用PHP,而不是使用C中的其他接口来管理回调。这个例子,对于一个'一个',你一定会把它做得更快。

我倾向于使用cron作业执行此任务,而不是在守护进程中轮询数据库。

很可能你的FFmpeg命令需要一段时间才能做到这一点,对吧? 在这种情况下, 真的有必要不断地查询数据库吗? cronjob每分钟运行一次(或者每5分钟,10分钟或20分钟)是不是一个简单的方法来实现同样的事情呢?

对于这种事情来说,Php并不比其他任何常见的脚本语言都好或者更糟。 它可以完全访问所有的系统调用和库工具,你需要做这样的工作。 如果你最喜欢使用PHP进行脚本编写,那么PHP将为你做这项工作。

唯一的缺点是,php并不像perl或python那样无处不在,它几乎安装在unix的所有风格上。 PHP只能在要提供动态Web内容的系统上找到。 不是一个PHP解释器太大或昂贵的安装,但如果你最关心的是让你的程序到很多系统,这可能是一个小小的障碍。

我会相反,并建议您尝试PHP守护进程。 这显然是你知道的最好的语言。 你大概会在任何情况下合并一个计时器,所以你可以复制数据库的查询频率。 只要你不是天真地循环查询就没有惩罚。

如果它不是经常执行,你可以选择从cron运行php,让你的代码耗尽队列然后死掉。

但是,不要害怕坚持你最了解的,作为第一个近似。

尽量不要使用触发器。 他们会施加不必要的耦合,他们没有乐趣去测试和调试。

如果不需要近乎即时的操作,cron-job可能会工作得很好。

我只是想根据队列守护进程“beanstalkd”来建立一个我所建立的系统。 我从PHP(这种情况下,PHP)的网页调用发送各种小消息到守护进程,然后一个PHP脚本从队列中选取它们并执行各种任务,如调整图像大小或检查数据库(通常通过Memcache传回信息基于商店)。

为了避免长时间运行的进程,我把它包装在一个BASH脚本中,根据脚本返回的值(“exit(1);”)将重新启动脚本,对于执行的每个(比如说)50个任务。 如果因为我计划重启,它会立即执行,任何其他退出值(默认值为0,所以我不使用它)会暂停几秒钟,然后重新启动。

正确守护PHP脚本的一个问题是,PHP没有与dup()或dup2()系统调用的接口,这是分离文件描述符所需的。

以明智的周期性进行cron作业,PHP脚本可以完成这项工作,生产稳定性是可以实现的。 您可能想要限制同步FFMpeg实例的数量,并确保具有完整的应用程序日志记录和异常处理。 我已经在Java中持续运行轮询过程,以及每十分钟一个cron的PHP脚本,而且都做得很好。

你可能要考虑做一个执行系统命令(即FFmpeg)而不是守护进程的mysql 触发器 。 如果有些滞后不是问题,那么你也可以在每隔几分钟执行一次的cron中加入一些东西来检查。 克朗是我的选择,如果它是一个选项。

为了回答你的问题,php作为守护进程运行是完全正常的。 这不需要在C中完成。

如果结合Kent Fredric,tokenmacguy和Domster的答案,你会得到一些有用的东西。

php可能不适合长时间的执行,所以让我们保持每个执行周期的简短,并确保操作系统负责清理任何内存泄漏。 作为一个启动你的PHP脚本的工具,cron可以成为一个好工具。 如果你这样做,语言之间没有太大的区别。

但问题依然存在。 PHP甚至能够作为一个正常的守护进程很长时间(几年)运行? 或者什么内存泄漏吃掉你所有的内存并杀死系统?

/约翰

如果你这样做,注意内存泄漏。 根据这个 (在5.3中修复),PHP 5.2在垃圾回收器方面有一些问题。 也许它更好地使用cron,所以脚本开始清理每一个运行。

对于你所描述的,我会去守护进程。 确保你在轮询循环中保持睡眠状态,这样当没有新的任务时,不会轰击数据库。 cronjob对工作流/报告类型的作业更好,在那里没有一些特定的事件触发下一次运行。

如前所述,PHP在内存管理上存在一些问题。 你需要确保你测试你的代码是否存在内存泄漏,因为这会随着时间的推移而长时间的运行。 PHP没有真正的垃圾收集 – 它依赖于引用计数,这意味着循环引用会导致泄漏。 如果你意识到这一点,你可以编码。

如果你确实决定遵循这个守护进程,那么最近在PHP v5.3.0安装中使用了一个名为System_Daemon PEAR模块。 这是作者的博客文档: http : //kevin.vanzonneveld.net/techblog/article/create_daemons_in_php

如果您已安装PEAR,则可以使用以下命令安装此模块:

 pear install -f System_Daemon 

您还需要创建一个初始化脚本: /etc/init.d/<your_daemon_name>

然后你可以:

  • 启动守护进程: /etc/init.d/projNotifMailDaemon start
  • 停止守护进程: /etc/init.d/projNotifMailDaemon stop

日志保存在:/ /var/log/<your_daemon_name>.log

我不会推荐它。 PHP不是为长期执行而设计的。 它的设计主要是短暂的页面。

根据我的经验,PHP可能会在某些较大的任务中泄漏内存。

一个cron作业和一点bash脚本应该是你所需要的一切。 你可以做这样的事情:

 $file=`mysqlquery -h server < "select file from table;"` ffmpeg $file -fps 50 output.a etc. 

所以bash将更容易编写,移植和维护恕我直言比使用PHP。

如果你知道你在做什么。 您需要了解您的操作系统。 PHP通常不适用于大多数守护进程,因为它不是线程化的,并且没有一个体面的基于事件的系统用于所有任务。 但是,如果它适合您的需要,那么没有问题。 现代PHP(5.3+)是非常稳定的,没有任何内存泄漏。 只要你启用GC,不要实现自己的内存泄漏等,你会没事的。

以下是我正在运行的一个守护进程的统计信息:正常运行时间17天(由于PHP升级,最后一次重启)。 写入的字节数:200GB连接:处理数百个连接,数十万个项目/请求处理:数百万

node.js通常更适合,虽然有一些小的烦恼。 在相同的领域已经做了一些改进PHP的尝试,但是它们并不是那么棒。

克伦工作? 是。

守护进程永远运行? 没有。

PHP没有垃圾收集器(或者至少,我上次检查没有)。 因此,如果你创建一个循环引用,它永远不会被清除 – 至少不会直到主脚本执行完成。 在守护进程中,这大概是从来没有。

如果他们在新版本中添加了GC,那么可以。

去吧。 我也必须做一次。 就像其他人所说的那样,这不是理想的,但会变得更完美。 使用Windows,对吗? 好。

如果你只是偶尔需要运行 (每小时一次等)。 为你的Firefox做一个新的快捷方式,把它放在相关的地方。 打开快捷方式的属性,将“Target”更改为:

 "C:\Program Files\Mozilla Firefox\firefox.exe" http://localhost/path/to/script.php 

转到控制面板>计划任务在快捷方式指向新的计划任务。

如果你需要不断运行或者不断地运行 ,那么你需要将脚本调试一下。

开始你的脚本

 set_time_limit(0); ob_implicit_flush(true); 

如果脚本使用循环(如while ),则必须清除缓冲区:

 $i=0; while($i<sizeof($my_array)){ //do stuff flush(); ob_clean(); sleep(17); $i++; }