从服务器进程获取实时反馈[在PHP中]

从服务器进程获取实时反馈[在PHP中],php,ajax,pthreads,fork,proc,Php,Ajax,Pthreads,Fork,Proc,要求: 我需要运行一个后台进程(根据用户请求)大约需要30到60秒才能完成。我想给用户一些状态反馈。注:托利是对的,不需要“背景” 什么在起作用: 这个过程在这段时间内打印了大约20条状态消息,我用proc_open检索它们,并使用fgets在读取管道上侦听它们。我可以将这些消息保存到会话变量中,并使用时间戳(以帮助调试),我可以看到随着进程的进行,会话数组将随着这些消息一起写入 麻烦: 我的计划是使用ajax调用(每秒)轮询服务器,以检索这些会话变量以在DOM中显示。瓶颈似乎是服务器在运行后台

要求:

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

什么在起作用:

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

麻烦:

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

明显的误解:

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

可能的解决方案:

  • 我不希望用户启动的进程运行此 过程/场景有那么重,但如果我能 在这个解决方案中构建,这将有助于减轻我的沉重负担 我想现在就这么做
  • 这是多线程(pthreads)还是 多进程(fork)解决方案
  • 或者,我应该保存一个进程id, 让我们用while(…fgets…)语句轮询它,然后 在服务器为ajax提供服务之后,返回到流程 请求
  • 我想我可以运行假状态消息,然后 完成后返回结果时,应准确响应。 处理请求的时间不取决于用户,因此 我的假计时可能相当准确。不过,我想 了解提供实时反馈的解决方案

  • 为什么你会认为你需要一个背景流程?还有,你从哪里得到你需要一个的想法

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

    更简单的是,由于您使用了会话(AJAX请求到一个单独的处理程序,该处理程序只检查会话中的内容,如果有smth new),将返回新的部分

    $_SESSION['progress'] = array();
    
    inside 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);})
    

    像这样的方法应该行得通。

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

    有一点重要的理论: -session_start()和$_session[“x”]=“y”之类的集合将始终锁定会话文件

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

    主要问题是,即使您在通过AJAX运行的进程中设置了$u会话,它也必须始终等待会话文件解锁,这将导致两个进程之间的同步(a.+B.)——两个进程同时完成

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

    %_SESSION["A"] = "B";
    $_SESSION["x"] = "y";
    session_write_close();
    
    PS:最好的方法是使用一组定制的函数来处理会话


    对不起,涨价了。我刚刚创建了一个stack帐户。

    您准确描述了我的方法,但我仍然列出了问题。如果我有一个while循环,它使我保持在proc_open管道上,即使它有一个sleep(),它似乎在ajax请求完成之前不会为其提供服务。我一直在卸缓冲区(所有缓冲区)。您认为ajax调用是由“单独的处理程序”处理的,这意味着一个单独的进程,因此我不需要创建单独的线程或进程。“单独的处理程序”意味着一个单独的php脚本。如果主进程是在process.php中完成的,那么在单独的文件中有第二个脚本来处理ajax请求。单独的处理程序和单独的进程(或进程中的另一个线程)都是不同的事情<代码>如果主流程完成…某种程度上总结了故障。在php中,除非采取步骤来处理进程/线程,否则sleep()是阻塞的,因此您的建议(实际上)是不可行的——它是可行的,但需要更详细的解释(在我看来,不值得)。感谢您的回复,但这并不能回答我的问题。正如我试图向您解释的那样,您不需要sleep()函数。假设您正在一个名为“process.php”的php脚本中执行一些操作,在执行这些耗时的操作时,您可以定期更新$\u会话变量。来自客户端的请求应该发送到不同的php脚本,我们称之为“ajax\u handler.php”。在“ajax\u handler.php”中,您可以访问$\u会话变量的当前值,并将进度返回到浏览器。除非您构建的php版本可以分叉进程或运行多个线程,否则您所建议的是不可能的;因为只是向不同的人发送一个请求