【问题标题】:start /B doesn't start the taskstart /B 不启动任务
【发布时间】:2014-07-27 23:23:05
【问题描述】:

我目前正在使用 PHP 启动一个异步作业来执行一些测试。

为了让它发挥作用,我在 SO 上找到了一些提示,例如使用 popen 和 start:

$commande = "testu.bat";
$pid = popen('start /B ' . $commande, 'r');
$status = pclose($pid);

testu.bat 的文件夹在我的用户路径中。

这个脚本执行一些任务,为了控制它的执行,它应该生成一个日志文件,但我从来没有得到它。

而如果我只是删除 /B 选项,它可以正常工作并且我会得到我的日志文件。

我是否错过了有关后台执行的某些内容?如何在后台运行时捕获错误信息?

【问题讨论】:

    标签: php windows shell phpunit command-line-interface


    【解决方案1】:

    您似乎在假设/B 切换到start 命令意味着“背景”的情况下进行操作。它不是。来自start的用法:

    B           Start application without creating a new window. The
                application has ^C handling ignored. Unless the application
                enables ^C processing, ^Break is the only way to interrupt
                the application.
    

    start 启动的进程默认是异步的。由于这似乎是您想要的,因此只需运行不带 /B 开关的命令即可。

    【讨论】:

      【解决方案2】:

      有趣的...好吧,这就是我的想法: 因为你是在后台运行任务,所以 PHP 脚本会继续执行,它不会等待 testu.bat 返回任何东西...

      或者换一种说法,popen 执行它被指示做的事情,即在后台启动任务(它确实如此),但随后控制权立即交还给 PHP,而日志文件仍在后台和php脚本同时进行...

      在这种情况下,我会做的是让 testu.bat 在完成处理后以回调类型的方式调用 php 脚本(或另一个 PHP 脚本),就像在 Javascript 中一样,您将使用回调进行异步Ajax 调用...

      也许将回调脚本命令作为参数提供给 testu.bat..?

      希望对您有所帮助...

      【讨论】:

        【解决方案3】:

        我不太确定您在这里的目标,但这里有一些您可能会用到的信息:

        为了找出后台错误,您可能会发现这些函数很有用:

        set_exception_handler();
        set_error_handler();
        register_shutdown_function();
        

        当然会将他们捕获的错误写到某个文件中。

        如果您不需要从请求中返回任何数据,您可以简单地使用:

        fsockopen()
        curl
        

        并给他们一个短暂的超时时间(10 毫秒)。脚本将在后台运行。

        或者,如果您确实需要返回数据,您可以将其放入数据库并设置一个循环来检查数据是否已被插入,或者只需将其输出到文件中并检查其是否存在。

        【讨论】:

        • 我的目标是从 Web 界面运行繁重的 PHP 脚本。用户不需要等待这个脚本的结束。所以它应该在后台运行。
        • 是的,实际上它应该使用线程运行,但是由于我的 windows 环境不支持创建线程,这是我使用的解决方法。您只需使用 fsockopen 或 curl ping 脚本并设置超时,主脚本不会等到 ping 的 sacript(线程)完成。一个简单的测试是您是否在浏览器中打开某些内容然后关闭它。该脚本将执行到最后。使用第二行有 sleep(10) 的简单 scipt 对其进行测试。
        【解决方案4】:

        在我看来start 通过在“后台”中创建一个新进程来启动指定的命令。因此,start 的执行本身“只是”启动了第二个进程并立即存在。 但是,使用/B 开关,要执行的命令将在start 进程的上下文中执行。因此start 进程的执行需要更长的时间。现在我怀疑执行pclose 会终止start 进程,因此您不会获得日志文件。

        也许一个解决方案(虽然不是 testet)可能正在执行类似 start /B cmd "/C testu.bat" 其中start 只是尝试执行cmd 和cmd 获取/C testu.bat 作为参数,这是它应该执行的“命令”。

        另一个想法: 如果不拨打$status = pclose($pid);会怎样?

        【讨论】:

        • 删除pclose()函数时脚本没有执行
        【解决方案5】:

        对于一些寻求这个技巧的人来说,在我的例子中,它只需要在 php.ini 或 PHP 平台函数中激活 PHP 指令 ignore_user_abort。

        如果没有激活它,进程会被 pclose() 杀死而不会完成工作。

        【讨论】:

          【解决方案6】:

          您的问题很可能通过使用队列系统得到妥善解决。您将作业插入到后台进程拾取并处理的队列中。通过这种方式,后台任务完全独立于发起任务的 HTTP 请求 - 但您仍然可以监控其进度。

          可以在您的场景中为您提供帮助的两个最受欢迎的软件包:

          1. Gearman

          2. RabbitMQ

          请注意,实施排队解决方案不是 5 分钟的前景,但它在技术上是适合这种情况的正确方法。对于公司产品,这是唯一可行的方法;对于一个你只想让某些东西起作用的个人项目,第一次完成它需要一定程度的承诺。如果您希望扩展您的开发视野,我强烈建议您尝试一下。

          【讨论】:

          • 你是真的,这是一个队列或 cron 系统的工作。这就是我最终实现的方式,但我仍然想了解/B 选项。
          猜你喜欢
          • 2012-09-09
          • 2018-11-10
          • 2022-07-15
          • 1970-01-01
          • 2015-03-17
          • 2018-08-01
          • 2021-01-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多