【问题标题】:Can Cron jobs be used to simultate multi threading with PHP?Cron 作业可以用来模拟 PHP 的多线程吗?
【发布时间】:2011-01-12 06:02:49
【问题描述】:

我有一个 mysql 数据库表,里面有 1000 多条记录,比如说 5000 条记录。每条记录都有一个processed 布尔标志,默认为false (0)。我想做的是每分钟在 cron 上运行一个 PHP 脚本。它的代码是这样的:

<?php
process();

function process()
{
   $sql = "SELECT id FROM items WHERE processed = '0' ORDER BY id ASC LIMIT 1";
   $result = $this->db->query($sql);

   if (! $result->has_rows())
     die;

   $id = $result->getSingle('id');
   processItem($id); //Will set processed to 1 after processing is done
   process();
}
?>

上面的代码应该很清楚了,它获取下一条未处理记录的id,处理它,然后再次调用process()函数,重复这个过程直到没有更多的项目待处理,此时执行将停止。

通过将此脚本放在 Cron 上以每分钟运行一次,我希望此脚本的多个实例都在同时处理项目,因此可以处理 5-10 多个项目,而不是一次处理一个项目同时。

1) 这会按照我的计划进行吗?有什么改进建议/需要注意的地方吗?

2) 我是否应该让脚本为正在运行的实例数设置一个计数器,所以每当 cron 作业启动时,它都会检查计数器,如果有 50 个(?)实例正在运行,它将退出而不进行处理。这可能会通过让太多正在运行的进程占用太多内存来防止服务器崩溃?有什么想法吗?

【问题讨论】:

  • 实际上,上面的代码似乎对limit 0没有做任何事情

标签: php multithreading cron


【解决方案1】:

我有几句话要说:

首先,您使用递归来处理多行。如果递归太深,这可能会导致问题。而是使用一个简单的循环。

其次,您知道这段代码是否可以从多次运行中受益?如果机器受 CPU 限制,它可能不会从另一个线程中受益。我建议你手动检查有多少线程工作得最好。更多的线程并不总是让事情变得更快,在某些情况下实际上会减慢一切。

最后,我肯定会限制这些脚本中有多少可以同时运行。这可以通过确保每个脚本运行不超过 5 分钟来实现。或者,您可以保留活动脚本的数量,并确保它不会超过您在我的第二个建议中确定的最大数量。

编辑:我添加了一些关于递归可能导致的问题的更多信息: 每次递归调用函数时,堆栈上都会用完额外的空间。该空间存储任何局部变量以及函数的地址(允许它在被调用函数退出时恢复状态)。堆栈只有有限的空间,因此最终您的程序将因堆栈溢出而崩溃。尝试运行这个简单的程序:

function a($i) { 
   print $i . "\n"; 
   a($i + 1);
}
a(0);

在我的系统上,PHP 在 608739 次迭代后崩溃。在更复杂的功能中,这个数字可能要小得多。一个简单的循环没有这些开销,因此它没有这个问题。

【讨论】:

  • 感谢您的回答。递归会导致什么问题?
  • 我已经回答了您关于递归可能在主要答案正文中引起什么问题的问题。
  • 谢谢伙计,特别是关于检查脚本是否已经运行了 5 分钟并终止的提示。感谢您的帮助:)
【解决方案2】:

递归似乎根本没有必要,就像 bramp 说的那样,可能会导致问题。为什么不只是

$sql = "SELECT id FROM items WHERE processed = '0' ORDER BY id ASC LIMIT 1";

while ( ($result = $this->db->query($sql) && $result->has_rows() ) {
   processItem( $result->getSingle('id') );
}

然而,我预见到这里会有更大的问题。如果您打算每分钟运行一次此脚本,您有什么机制来停止执行可能仍在运行的先前执行的脚本?您最终可能会多次处理同一个 ID。

如果您绝对需要(伪)多线程方法,我建议如下:

  1. 获取一系列或所有未处理的 ID,而不是一次一个。
  2. 使用curl_multi_ 系列函数,将上述结果的子集(n id 的组)传递给另一个脚本以进行实际处理。

这种方法可以让你更好地控制整个过程,避免不必要的单查询获取未处理的ID。

【讨论】:

    【解决方案3】:

    我启动了一个项目来解决完全相同的问题。它可以持续运行脚本,并在需求量大的情况下并行运行更多实例。如果没有什么可做的,那么它将在运行脚本实例之前等待指定的时间间隔。

    如果您有兴趣,请阅读一些用例:www.4pmp.com/fatcontroller/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-03
      • 2020-03-24
      • 2011-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-18
      • 2019-06-03
      相关资源
      最近更新 更多