【问题标题】:Getting real time feedback from a server process [in PHP]从服务器进程获取实时反馈 [in PHP]
【发布时间】:2014-04-13 20:07:45
【问题描述】:

要求:

我需要运行一个后台进程(根据用户请求),该进程大约需要 30 到 60 秒才能完成。我想给用户一些状态反馈。 注意:Toly 是对的,“背景”不是必需的。

工作原理:

该过程在此期间打印大约 20 条状态消息,我使用 proc_open 检索它们并使用 fgets 侦听读取管道。我可以将这些消息保存到会话变量中并使用时间戳(以帮助调试)我可以看到会话数组随着进程的进行被这些消息写入。

麻烦:

我的计划是使用 ajax 调用(每秒)轮询服务器以检索这些会话变量以在 DOM 中显示。瓶颈似乎是服务器在运行后台进程时无法为 ajax 请求提供服务。后台进程完成后,所有内容都会立即转储。据我所知,问题不在于输出缓冲,因为使用与每个进程消息一起保存的(调试)时间戳显示服务器正在按顺序写入会话 var,所以这就是我知道 proc_open 和管道读取按我预期工作的方式.问题似乎是服务器无法向 AJAX 请求提供它的 JSON 对象,直到它完成该过程;或者,可能更准确地说,是通过读取管道的循环完成。

明显的误解:

我认为将进程发送到后台(使用 &)可能会给我一个解决方案。显然我不知道后台进程和分叉进程之间的区别。在这种情况下,通过在后台运行进程似乎对我没有任何影响,可以获得什么好处(如果有的话)?

可能的解决方案:

  1. 我不希望用户启动的进程运行这个 过程/场景要那么重,但如果有什么我可以 内置到这个解决方案中,这将有助于繁重的负载,然后我会 现在喜欢这样做。
  2. 这是多线程 (pthreads) 还是 多进程(分叉)解决方案?
  3. 或者,我应该保存一个进程 ID, 用 while( .. fgets ..) 语句轮询它,然后 服务端处理完ajax后回到流程 要求?
  4. 我想我可以运行虚假状态消息,然后 完成后返回结果时准确响应。 处理请求的时间不取决于用户,所以 我的假时间可能非常准确。但是,我想 知道提供实时反馈的解决方案是什么。

【问题讨论】:

    标签: php ajax pthreads fork proc


    【解决方案1】:

    在谷歌搜索了一天以获得与您在此处描述的相同行为的技术之后,我为我的项目提出了一个简单的解决方案。

    一个重要的理论: - session_start() 和 $_SESSION["x"] = "y" 这样的集合将始终锁定会话文件。

    案例场景: - A - process.php - 通过 ajax 调用运行 - B - get_session.php - 第二个 ajax 调用;

    主要问题是/曾经是,即使您在通过 AJAX 运行的进程中设置了 $_SESSION,它也总是必须等待会话文件解锁,这将导致两者之间的同步两个过程 (A. + B.) - 同时完成!

    因此,解决此问题并获得良好结果的最简单方法是在每组之后使用 session_write_close()。例如:

    %_SESSION["A"] = "B";
    $_SESSION["x"] = "y";
    session_write_close();
    

    PS:最好的方法是使用一组自定义函数来处理会话。

    抱歉加价。我刚刚创建了一个堆栈帐户。

    【讨论】:

      【解决方案2】:

      您为什么认为需要后台进程?另外,您从哪里得到需要一个的想法?

      一个普通的 php 脚本,设置了足够的超时时间,在每一步都使用了 flush() 函数,将为您提供 AJAX 所需的输出。

      更容易的是,因为您使用会话 - 向单独的处理程序发出 AJAX 请求,它只会检查会话中的内容,如果有新的东西 - 将返回新的部分。

      $_SESSION['progress'] = array();
      

      在process.php中

      $_SESSION['progress'][] = 'Done 5%';
      // complete some commands
      $_SESSION['progress'][] = 'Done 10%';
      

      在 ajax.php 中

      if(count($_SESSION['progress']) > $_GET['laststep']) {
          // echo the new messages
      }
      

      在您的普通页面内

      $.ajax('ajax.php', 'GET', 'laststep=1', success: function(data){ show(data);})
      

      类似的东西应该可以工作。

      【讨论】:

      • 您准确地描述了我的方法,但我仍然列出了问题。如果我有一个 while 循环让我保持在 proc_open 管道上——即使它有一个 sleep()——它似乎在完成之前不会为 ajax 请求提供服务。我一直在转储缓冲区(所有缓冲区)。您认为 ajax 调用是由“单独的处理程序”处理的——这意味着一个单独的进程,因此我不需要创建一个单独的线程或进程的想法?
      • 'separate handler' 表示一个单独的 php 脚本。如果主进程在 process.php 中完成,则在单独的文件中创建第二个脚本,用于处理 ajax 请求
      • 拥有单独的处理程序和单独的进程 - 或进程中的另一个线程 - 都是不同的东西。 If the main process is done... 总结了这个麻烦。在 php 中,除非采取措施解决进程/线程,否则 sleep() 会阻塞,因此您的建议(实际上)是不可行的——它是可行的,但有更详细的解释(在我看来,不值得)。感谢您的回复,但这并不能回答我的问题。
      • 正如我试图向您解释的那样 - 您不需要 sleep() 函数。假设您正在一个名为“process.php”的 php 脚本中执行一些操作 - 在执行这些耗时的操作时,您可以定期更新 $_SESSION 变量。来自客户端的请求应该发送到不同的 php 脚本,我们称之为“ajax_handler.php”。在 'ajax_handler.php' 中,您可以访问 $_SESSION 变量的当前值并将进度返回给浏览器。
      • 除非您构建一个可以分叉进程或运行多个线程的 PHP 版本,否则您的建议是不可能的;因为仅仅向不同的脚本发送请求并不意味着如果解释器正忙于执行其他操作,它将(立即)运行 - 因此理解 PHP 是开箱即用的单线程。请 google pThreads 和 Zend Thread Safety (ZTS) 以更好地了解这些东西如何协同工作以在 PHP 环境中实际提供多线程功能。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-27
      • 2010-11-19
      • 1970-01-01
      • 2018-01-14
      • 1970-01-01
      相关资源
      最近更新 更多