【问题标题】:php call class method asynchronouslyphp异步调用类方法
【发布时间】:2015-03-31 07:42:04
【问题描述】:

我需要在循环中异步调用 PHP 方法。

这是我尝试过的:

foreach ($batch_ids as $batch_id) {
          $this->launchBackgroundProcess( $this->sendBatchMail($batch_id) );
        }

public function launchBackgroundProcess($call) {

  // pclose( popen( $call.'/dev/null &', 'r'));     
  Proc_close( Proc_open( $call.' > /dev/null & ', 'r'));
  return true;
}

现在的错误是我的函数 sendBatchMail 被直接调用并且 launchBackgroundProcess 从未被调用(使用 echo/print/log 来检查)。

因此,如果在一个批次 ID 中有 10k 封邮件,则下一个批次 ID 的 endBatchcMail 永远不会启动。

我希望在后台同时异步调用 sendBatchMail 以获取所有批次 ID。

我不是很精通 pthreads...而且似乎是我的最后一站。

【问题讨论】:

    标签: php exec background-process popen


    【解决方案1】:

    这不是真正要走的路。每个 PHP 进程都会针对每个单独的请求启动和拆除。您不应该尝试直接从响应 HTTP 请求的 PHP 脚本直接启动任何内容。它唯一的工作应该是尽快返回 HTTP 响应然后挂断。任何更大量的工作都应该排队等待稍后由更持久的后端工作人员处理。

    这直接将我带到消息队列和工作人员。查看Gearman 以获得一个非常简单的此类系统,尽管还有许多其他可能性,包括ØMQ、Redis 和其他。您只需在此队列中填充大量消息,然后由一个或多个 PHP 脚本处理,这些脚本作为 cron 作业或后台的持久工作守护进程运行,与前端 HTTP 处理程序完全分离。

    【讨论】:

    • 非常感谢 deceze。我这个运行邮件的 php 方法本身是通过 cron 执行的。但我希望这最终也能同步各个 batch_id 调用。将通过链接更好地理解您的建议。
    • 基本上您希望许多进程并行运行。 “异步性”只是切线的。由于 PHP 并不是真正的异步语言,因此实现这一目标的最佳方法是控制并行进程的数量和运行的工作人员数量,并控制这些工作人员通过消息队列从何处获取工作。
    【解决方案2】:

    一种方法是使用带有发送代码的 php 脚本,然后执行以下操作:

    shell_exec("theBackgroundScript.php >/dev/null &");
    

    但这意味着您将同时拥有很多进程。此外,如果其中一个由于某种原因失败,则很难找到并再次运行它。

    相反,请考虑在您的数据库中创建一个表来保存所有邮件作业。可能是这样的:

    CREATE TABLE email_jobs (
    id INTEGER AUTO_INCREMENT PRIMARY KEY,
    executed TINYINT DEFAULT 0,
    destination VARCHAR(255) NOT NULL,
    subject VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    created_at DATETIME NOT NULL,
    updated_at DATETIME DEFAULT NULL);
    

    然后,您只需要在需要时添加每个作业的详细信息:

    $db->query("INSERT INTO email_jobs (destination, subject, content, created_at) VALUES ('someperson@example.com', 'some subject', 'some email content', NOW())");
    

    然后,您需要一个 PHP 脚本来查询数据库中尚未执行的作业:

    $row = $db->query("SELECT * FORM email_jobs WHERE executed = 0 LIMIT 1");
    // ... send email described in $row
    

    脚本获取第一个未执行的作业(或前 N 个未执行的作业),并将其发送。 然后你只需要将脚本放入cron 并让它发送所有电子邮件。

    如果一个失败了,很容易再次发送,只需将execute设置为零,就可以发送了。

    【讨论】:

    • 您的 shell_exec 解决方案对我来说完美无缺。非常感谢!
    猜你喜欢
    • 2014-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 2015-11-28
    相关资源
    最近更新 更多