我有一个PHP脚本需要很长时间(5-30分钟)才能完成.为了防止重要,脚本使用curl从另一台服务器中抓取数据.这就是它花了这么长时间的原因; 它必须等待每个页面加载,然后再处理它并移动到下一页.
我希望能够启动脚本并让它完成,直到它完成,这将在数据库表中设置一个标志.
我需要知道的是如何在脚本运行完成之前结束http请求.另外,php脚本是最好的方法吗?
当然可以用PHP完成,但是你不应该将它作为后台任务 - 新进程必须从启动它的进程组中分离出来.
由于人们对此常见问题解答给出了同样错误的答案,我在这里写了一个更全面的答案:
http://symcbean.blogspot.com/2010/02/php-and-long-running-processes.html
来自评论:
简短的版本
shell_exec('echo /usr/bin/php -q longThing.php | at now');
只是在这里包含有点长的原因.
快速而肮脏的方式是ignore_user_abort
在php中使用该功能.这基本上说:不关心用户做什么,运行此脚本直到完成.如果它是一个面向公众的站点,这有点危险(因为有可能,如果它启动了20次,你最终会同时运行20个++版本的脚本).
"干净"方式(至少是恕我直言)是设置一个标志(例如在数据库中),当你想要启动进程并每小时(或左右)运行一个cronjob来检查是否设置了该标志.如果设置了,则长时间运行的脚本会启动,如果未设置,则不会发生.
您可以使用exec或system来启动后台作业,然后执行该操作.
此外,还有更好的方法来抓取您正在使用的网络.您可以使用线程方法(多个线程一次执行一个页面),或者使用eventloop(一个线程一次执行多个页面).我使用Perl的个人方法是使用AnyEvent :: HTTP.
ETA:symcbean解释了如何在这里正确分离后台进程.
不,PHP不是最好的解决方案.
我不确定Ruby或Perl,但是使用Python,您可以将页面刮板重写为多线程,并且它可能至少运行20倍.编写多线程应用程序可能有点挑战,但我编写的第一个Python应用程序是多线程页面刮刀.您可以通过使用其中一个shell执行函数从PHP页面中调用Python脚本.
是的,您可以在PHP中完成。但是除了PHP,使用队列管理器是明智的。这是策略:
将大型任务分解为较小的任务。在您的情况下,每个任务可能只加载一个页面。
将每个小任务发送到队列。
在某个地方运行您的队列工作者。
使用此策略具有以下优点:
对于长时间运行的任务,如果在运行过程中出现致命问题,它具有恢复的能力-无需从头开始。
如果不必按顺序运行任务,则可以运行多个工作程序来同时运行任务。
您有多种选择(仅几个):
RabbitMQ(https://www.rabbitmq.com/tutorials/tutorial-one-php.html)
ZeroMQ(http://zeromq.org/bindings:php)
如果您使用的是Laravel框架,则队列是内置的(https://laravel.com/docs/5.4/queues),带有适用于AWS SES,Redis和Beanstalkd的驱动程序