PHP foreach 用户脚本似乎使 apache 挂起


PHP foreach user script seems to make apache hang

我做了一个非常简单的脚本来遍历所有用户,每次执行限制为 500 个。

它执行以下操作:

  1. 选择用户数据
  2. 插入一行
  3. 向用户发送电子邮件
  4. 更新行
  5. 下一个用户

它按预期工作并成功完成。

但是当我运行它时,我无法在另一个窗口中使用该网站,因为它只是"加载"直到此脚本完成执行?

就好像脚本在运行时锁定了用户表,但这不应该发生,因为我们只是使用保存到$result的数据?

但是我可以在网站冻结时通过 sqlyog 查询数据库,所以不可能这样吗?会不会只是使用了太多资源?

脚本 - 示例

<?
set_time_limit(0);
require '../connect.php';
require '../includes/ses.php';
$i = 1;
$ses = new simpleemailservice();
$result = mysql_query("SELECT id, username, email FROM `user` WHERE thiscol = 0 LIMIT 500");
while($row = mysql_fetch_row($result)){
    mysql_query("INSERT INTO table (data) VALUES (1)");
    $m = new SimpleEmailServiceMessage();
        $m->addTo($row[1]." <".$row[2].">");
        $m->setFrom("Emailer <no-reply@emailer.com>");
        $m->setSubject("Subject");
        $m->setMessageFromString("Email Text", "Email HTML");
    if($ses->sendEmail($m))
        mysql_query("UPDATE `user` SET thiscol = 1 WHERE id = ".$row[0]);
    $i++;
}
?>

这种行为听起来像会话锁定。PHP 会话的默认工作方式是锁定会话(以防止两个进程写入会话对象)。对于典型的短寿命 PHP 脚本来说,这通常没问题,但当你有长时间运行的东西时,可能会咬你。

如果你的应用程序根本没有使用会话,那么你应该在php.ini或.htaccess中关闭session.auto_start:http://www.php.net/manual/en/session.configuration.php#ini.session.auto-start(如果你在那里没有看到它,或者它已经关闭,但你正在使用某种框架,框架可能会为你启动会话;如果是这样,转到下一个解决方案比尝试对抗框架更简单。

如果您在某些页面上使用会话,但不在此长时间运行的过程中使用会话,则解决方案是在脚本开始时使用 session_write_close() 关闭会话:

<?
set_time_limit(0);
require '../connect.php';
require '../includes/ses.php';
session_write_close();
$i = 1;
....
再次,框架

警告:如果框架正在为您启动会话,则在包含框架文件之后放置session_write_close();,而不是之前!(您在评论中提到就是这种情况,这就是为什么我将其放在要求行之后的原因。

如果长时间运行的进程需要使用会话,但为只读,则上述方法仍然有效。见 https://stackoverflow.com/a/14409902/841830(如该答案所示,如果您需要在长时间运行的进程结束时写入会话,这也是可能的。

(附言这已经在评论中得到了回答,但我已经接受了 Wrikken 的提议,将其作为答案发布。是的,谣言是真的:我会为几个代表做任何事情......