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

时间:2009-03-14 23:29:53

标签: php c linux daemon

我希望创建一个后台进程,我被告知这些通常是用C语言编写的。我最近发现PHP可以用来创建一个守护进程,我希望得到一些建议,如果我应该以这种方式使用PHP。

以下是我对守护程序的要求。

  • 不断检查是否有行 添加到MySQL数据库表
  • 运行FFmpeg命令 从数据库中检索
  • 将输出插入MySQL表

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

它甚至会产生很大的性能差异吗?

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

全部谢谢

17 个答案:

答案 0 :(得分:29)

正如其他人所说,各种版本的PHP都有垃圾收集器的问题。当然,如果您知道您的版本没有此类问题,则可以消除该问题。关键是,你知道(肯定),直到你编写守护进程并通过valgrind运行它,看看安装的PHP是否在任何给定的机器上泄漏。所以在这一方面,你可以写它只是为了发现Zend认为修复的东西可能仍然是错误的,或者你正在处理稍微旧版本的PHP或某些扩展。恶心。

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

所以,我建议:

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

我是一个非常死的C人。但是,我认为用PHP快速敲击一些东西是没有错的(除了我解释过的情况)。我也发现使用PHP来构建可能会或可能不会在C中重写的东西也没有错。例如,如果使用PHP,处理数据库的东西会更简单,而不是使用C中的其他接口来管理回调。所以在那个例子,对于'一次性',你肯定会更快地完成它。

答案 1 :(得分:17)

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

你的FFmpeg命令可能需要一段时间才能完成它,对吧?在这种情况下,是否真的必须不断轮询数据库?每一分钟(或者每五分钟,十分钟或二十分钟)运行的cronjob不是更简单的方法来实现同样的目标吗?

答案 2 :(得分:7)

对于这种事情来说,Php并不比任何其他常见的脚本语言更好或更差。它可以完全访问您执行此类工作所需的所有系统调用和库实用程序。如果您最熟悉使用PHP编写脚本,那么php将为您完成这项工作。

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

答案 3 :(得分:6)

我会反对并建议你试试php守护进程。这显然是你认识最好的语言。在任何情况下,您都可能会使用计时器,因此您可以在数据库上复制查询频率。只要你没有天真地循环查询,就没有任何惩罚。

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

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

尽量不要使用触发器。它们会产生不必要的耦合,测试和调试它们并不好玩。

答案 4 :(得分:4)

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

答案 5 :(得分:3)

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

我正准备将基于排队守护进程'beanstalkd'的系统建立起来。我从(在这种情况下,PHP)网页调用发送各种小消息到守护进程,然后PHP脚本从队列中拾取它们并执行各种任务,例如调整图像大小或检查数据库(通常通过Memcache传回信息)的商店)。

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

答案 6 :(得分:2)

作为一个具有明确周期性的cron作业运行,PHP脚本可以完成这项工作,并且生产稳定性当然是可以实现的。您可能希望限制同时FFMpeg实例的数量,并确保具有完整的应用程序日志记录和异常处理。我已经在Java中实现了连续运行的轮询过程,以及每十分钟一次的cron'd PHP脚本,并且两者都很好地完成了工作。

答案 7 :(得分:1)

您可能需要考虑创建一个执行trigger命令(即FFmpeg)而不是守护进程的mysql system。如果某些延迟不是问题,您还可以在cron中放入一些每隔几分钟执行一次检查的内容。如果是选项,Cron将是我的选择。

要回答你的问题,php完全可以作为守护进程运行。它不必在C中完成。

答案 8 :(得分:1)

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

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

但问题仍然存在。 php是否能够长时间(几年)作为普通守护进程运行? 或者各种记忆泄漏会占用你所有的公羊并杀死系统?

/约翰

答案 9 :(得分:1)

如果这样做,请注意内存泄漏。根据{{​​3}}(在5.3中修复),PHP 5.2的垃圾收集器存在一些问题。也许最好使用cron,因此脚本每次运行都会开始清理。

答案 10 :(得分:1)

如果您决定沿着守护程序路线走下去,那么我最近在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

答案 11 :(得分:1)

对于你所描述的内容,我会选择一个守护进程。确保在轮询循环中保持睡眠状态,这样在没有新任务时就不会轰炸数据库。 cronjob更适用于工作流/报告类型的作业,其中没有某些特定事件会触发下一次运行。

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

答案 12 :(得分:0)

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

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

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

答案 13 :(得分:0)

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

根据我的经验,PHP可能会出现一些较大任务泄漏内存的问题。

答案 14 :(得分:0)

一个cron作业和一些bash脚本应该是你需要的一切声音。你可以这样做:

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

所以bash比使用PHP更容易编写,移植和维护IMHO。

答案 15 :(得分:-2)

Cron的工作?是。

永远运行的守护进程?否。

PHP没有垃圾收集器(或者至少,我上次检查时没有)。因此,如果您创建循环引用,它永远不会被清除 - 至少在主脚本执行完成之前。在守护进程中,这几乎从不。

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

答案 16 :(得分:-5)

去吧。我也必须做一次。 像其他人说的那样,它并不理想,但它会完成。使用Windows,对吗?好。

如果您只需要偶尔运行(每小时一次等)。 为firefox创建一个新的快捷方式,将其放在相关的位置。 打开快捷方式的属性,将“目标”更改为:

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

转到“控制面板”&gt;“计划任务” 将新计划任务指向快捷方式。

如果你需要它不断运行或伪持续,你需要稍微调整一下脚本。

使用

启动脚本
set_time_limit(0);
ob_implicit_flush(true);

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

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