【问题标题】:Forking in PHP on Windows在 Windows 上使用 PHP 分叉
【发布时间】:2011-01-28 07:37:13
【问题描述】:

我们在 Windows 服务器上运行 PHP(确实是许多问题的根源,但目前还不能选择迁移)。在某些情况下,用户发起的操作需要启动一些需要一段时间的事情,用户不需要知道他们是成功还是失败,例如发送电子邮件或确保某些事情第三方帐户已更新。如果我可以用pcntl_fork() fork,这将非常简单,但是 PCNTL 函数在 Windows 中不可用。

似乎我能得到的最接近的就是做这种性质的事情:

exec( 'php-cgi.exe somescript.php' );

但是,这会复杂得多。我需要启动的操作依赖于运行过程中已经存在的大量上下文;要使用上面的示例,我需要找出基本数据并以某种方式将其提供给新脚本。如果我可以分叉,那只是让父进程早点返回,让子进程处理更多事情。

我发现一些人谈论他们自己在 Windows 上编译各种 PCNTL 函数的工作,但似乎没有任何可用的东西(断开的链接等)。

尽管this question 与我的名字几乎相同,但似乎问题在于执行超时而不是需要分叉。那么,我最好的选择是重构一点来处理调用 php-cgi,还是有其他选择?

编辑:似乎exec() 对此不起作用,至少在我没有弄清楚它的其他方面时不会,因为它会等到调用返回。我想我可以使用START,有点像exec( 'start php-cgi.exe somescript.php' );,但它仍然要等到其他脚本完成。

【问题讨论】:

  • 您是否考虑过为此使用 cron 作业? (有一些可用的选项,google.com/search?q=cron+windows
  • 据我所见,它看起来和使用 psexec 一样好用,但我只是用 psexec 来工作,所以我可能会坚持下去。

标签: php windows fork


【解决方案1】:

installing psexec 怎么样,然后使用 -d(不要等待)option

exec('psexec -d php-cgi.exe somescript.php');

【讨论】:

  • 太好了,我得到了它的工作。我对为什么用start 执行不能做我需要的事情感到困惑。此外,我需要使用 -accepteula 参数调用 psexec,即使我已经手动接受它自己在服务器上运行它。
  • 如果您正在寻找一种传递变量的方法,请使用 exec("psexec -d php-cgi.exe somescript.php 'var1' 'var2' 'var3'"); 然后在将变量发送到的 php 脚本中,使用 $argv[1]$argv[2] 和 @987654329 @.
【解决方案2】:

获取PSExec 并运行命令:

exec("psexec -d php-cgi.exe myfile.php");

【讨论】:

  • 这个答案确实有链接,但另一个没有
【解决方案3】:

PSTools 是一个很好的补丁,但我将把它留在这里:
如果您的服务器运行 Windows 10 并且具有最新更新,您可以安装一个 Linux 子系统,该子系统具有自己的支持本机分叉的内核。 这是微软官方支持的。

这里有一个good guide 说明如何操作。

一旦你安装了子系统本身,你需要在子系统上安装 php。

您的 windows "c:\" 驱动器可以在 "/mnt/c" 下找到,因此您可以从支持 fork 的子系统运行 php(并且通过扩展子系统的 php 可以使用 pcntl_fork)。

示例:php /mnt/c/xampp/htdocs/test.php

如果你想直接从 Windows 命令行运行子系统的 php,你可以简单地使用“wsl”命令。

假设您从“C:\xampp\htdocs\”下运行它
示例:wsl php main.php

“wsl”命令会为你解析路径,所以你不需要做任何黑魔法,如果你在c:\xampp\htdocs下调用该命令,子系统会将它解析为“/mnt/ c/xampp/htdocs/"。

如果您将服务器作为 apache 服务器 运行,您实际上不需要做任何额外的事情,只需停止 windows apache 服务器并启动 linux 即可。 显然,您需要在子系统上安装所有缺少的 php 模块。

【讨论】:

    【解决方案4】:

    您可以创建一个守护进程/后台进程来运行代码(例如发送电子邮件),请求只需将项目添加到队列中,让守护进程完成繁重的工作。

    例如,一个文件send_emails.bat

    cls
    C:\PHP533\php.exe D:\web\server.php
    exit
    

    打开 Windows 任务计划程序,并让上述 send_emails.bat 每 30 分钟运行一次。确保一次只运行一个实例,否则您可能会多次运行每个任务,或者将每封电子邮件发送两次。我说 30 分钟,以防万一出现暂时中断(内存问题、数据库不可用等),它将每 30 分钟重新启动一次,而不是有一个永无止境的进程。以下是一个骨架守护进程...未完成或未测试我只是打出一个示例:

    <?php
    set_time_limit(60*30); // don't run
    $keepgoing = true;
    $timeout = time()+ 60*29; // 29 minutes
    
    while(time() < $timeout)
    {
        // grab emails from database
        $result = $db->query('select subject, body, to_email FROM email_queue');
        if($result->num_rows == 0)
        {
            sleep(10); // so we are not taxing the database 
        }
        else
        {
            while($row = $result->fetch_assoc())
            {
            // send email
            }
        }
    }
    exit;
    ?>
    

    最后,您只需要请求将项目添加到数据库中的队列中,并让守护进程处理繁重的工作。

    $db->query('insert into email_queue(to,subject,body) values ('customer@email.com','important email','<b>html body!</b>');
    

    【讨论】:

      猜你喜欢
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 2014-07-19
      • 1970-01-01
      • 2021-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多