PHP或Java来处理长时间运行的后台请求

时间:2014-12-12 03:44:15

标签: php ajax multithreading

这是一个设计问题,我感谢您的见解/建议。我理解这个问题根据经验可能有不同的答案,我只是在选择如何进行之前寻求一些指导。

背景 - 我的应用程序主要基于LAMP堆栈 - Linux,Apache,MySQL和PHP。我还使用jQuery来进行客户端脚本编写,应用程序非常简单并且执行速度非常快。我也在使用CakePHP框架

场景#1 -

  1. 用户点击网页上的链接
  2. 点击会触发对服务器上的PHP脚本的AJAX调用
  3. PHP脚本向另一个网址发出cURL请求以处理一些信息,通常在4-5秒内返回
  4. 返回后,PHP脚本完成执行并终止
  5. 问题 -

    1. 我一直听说PHP是同步的,并且会在此请求完成之前挂起 - 所以如果多个用户在上述场景中发出多个请求,那么PHP会挂起,直到每个请求都按顺序处理,或者Apache负责生成多个线程来处理每个网络请求单独?
    2. 我试图找到一种更好地处理这个问题的方法 - 即使这意味着我应该走出PHP之外。你会建议我使用PERL脚本来处理cURL请求,只是让PHP派一个shell线程并退出或者更好的是创建一个AJAX可以调用的JAVA servlet,因为JAVA是多线程的,它可以在同一个上面处理它
    3. 我正在阅读pThreads - 这是pThreads会出现的情况
    4. 情景2

      1. 用户上传zip文件并单击流程按钮,然后退出应用程序
      2. 单击进程按钮后,会向服务器发送AJAX请求以处理zip文件。接收此请求的PHP脚本已启用ignore_user_abort,因此即使用户退出也会执行。
      3. 但是,处理此zip文件可能需要几分钟,因为它涉及跨Web服务器的多个cURL调用和SOAP调用
      4. 处理完成后,PHP脚本将更新数据库并终止
      5. 问题

        1. 再次类似于上面的问题,如果有多个人同时上传文件,这会阻塞吗?
        2. 假设PHP会将所有各种请求排队 - 这会导致超时情况和请求丢失吗?
        3. 使用PERL / JAVA等可以做得更好吗?
        4. 感谢您的建议和见解

2 个答案:

答案 0 :(得分:1)

简短的回答是

情景#1

  1. 所有/大多数语言是同步的,即表示运行ajax是异步的,并且通过ajax运行php的扩展是异步的。事情就是在这里你很困惑"同步"在这种情况下,它意味着阻止直到操作完成或进程阻塞,并行处理或甚至多线程。

  2. 再次多线程与并行处理完全不同,php完全能够运行几十个并行进程。它是最好的语言,可能不是,但它可以用尽可能少的工作来运行带有exec的shell脚本和linux上的这个exec(usr/bin/php -f pathtophpfile/index.php arg1 > /dev/null & );命令。多线程的定义如下:

  3.   

    多线程是程序或操作系统进程的能力   一次管理多个用户的使用,甚至管理   同一用户的多个请求,而不必具有多个   计算机中运行的程序的副本

    并行处理定义为此

      

    并行处理是同时使用多个CPU或   处理器核心来执行程序或多个计算线程。

    因此,虽然技术上php无法执行其中任何一项操作,但您可以在同一台计算机上同时运行多个php副本,就像您可以手动打开多个shell窗口并在每个shell中运行命令一样。是并行处理还是多线程?不,它只是同时运行多个PHP副本。

    1. 但任何"多线程或并行处理"是竞争条件。如果你小心避免它们,你会没事的。比赛条件就像这样

      • process1加载text.txt
      • process1进行更改
      • process2加载text.txt - 在process1保存其数据之前
      • process2进行更改
      • process2保存更改
      • process1保存更改
    2. 现在您将丢失process2所做的任何更改,因为process1将数据存储在内存中,并且从不考虑process2更改它。这也是我所谓的并发问题,它们基本上是一回事。如果使用CRON或其他一些基本的排队方法,另一件需要注意的事情就是不要用多个进程来完成同样的工作。

      同样调试可能是一个挑战,任何后台进程都是如此,而不是特定于php。最简单的方法是使用文件将输出记录为ob_start()& $var = ob_get_clean()(输出缓冲)并录制。使用关闭处理程序记录错误(例如

      )也很有用

      http://php.net/manual/en/function.register-shutdown-function.php

      当然,这些都是简化的例子,解释,但这是它的要点。

      情景#2

      1. 怎么会这样?正如我所提到的,php和Apache可以同时为超过200个客户端提供服务,另一个请求只是与Apache的另一个连接(当使用ajax或CURL时),但即使只使用CLI(命令行界面)它也基本相同。没有固有的原因你不能同时运行几十个php进程。

      2. 如何排队,他们只需再次执行,就像在浏览器中选择多个标签一样。至于超时,无论您使用何种语言,服务器上始终都有资源限制。您可以使用排队系统来确保在给定时间只处理少量文件,这可以像cron一样简单,也可以是具有某些状态列的数据库表,例如排队,运行,完成。然后cron脚本运行一个标记为排队的作业,在运行时将其标记为正在运行,标记完成后完成,冲洗并重复。

      3. 这是一个意见问题,更多的是你对这些语言的能力问题。

      4. 我实际上是在php中构建一个系统,它接受一个csv文件并将其分成25000个行块(不重写单独的文件,只读取多个线程的同一文件中的偏移量)。然后由最多10名工作人员并行处理这些块,然后将它们聚合在一起,然后生成一些报告和电子邮件等。这样做很容易,不。有可能,肯定是。

        我正在构建的系统例如采用一个100万行+的文件,并查询超过700k记录的数据库。它有点像这样

        作业预处理(一个进程创建多个块)

        1. 创建工作文件
        2. 计算设置
        3. 队列(在rabbitMq中)多个作业
        4. 进程(多个进程分别处理一个或多个块)

          1. 从队列
          2. 加载数据
          3. 在offset处访问input_file.csv并读取到offset的结尾
          4. 为每个块生成编号的结果文件,例如0.csv,1.csv
          5. 聚合(仅一个进程,接收作业的位)

            1. 加载以前保存的作业文件(来自步骤1)
            2. 当每个chunk完成作业文件中的记录
            3. 完成所有块后,按顺序压缩编号文件中的所有结果。
            4. 这里的技巧是多个处理部分(步骤2)在步骤1中没有触及该作业文件(或者它将遇到竞争条件),此外只有一个进程接收作业的所有块。一旦收到所有的块,我们将它们压缩成一个文件做一些清理,然后发送电子邮件等。

              有了这个,我在2分钟内运行了一个包含100万行的文件。使用单个线程/进程运行相同的文件大约需要15分钟。

              所以(再次)我向你保证它可以做到,它很棘手,你必须非常小心你如何移动你的数据,但在php中做这些事情并非不可能。 PHP和现代硬件可以一秒钟处理数千个操作。通常瓶颈在数据库中索引不好或等待网络连接等......

              如果你打算做一些真正重要的工作,我建议你像我一样(RabbitMq)调查排队或消息系统,但这可能在你的情况下有点过分。我使用排队系统来帮助保持流程清晰,避免竞争条件,基本上我唯一的目的就是组织数据流。

答案 1 :(得分:1)

场景#1

  • 1)PHP是同步的,但问题很混乱。 PHP通常会同步执行指令,但是Apache定义了处理模型。 Apache将重用或生成一个工作进程或线程来处理请求,直到达到配置的限制。
  • 2)你处理它的方式很好,你可能想尝试减少更新用户界面所需的时间,因为4-5秒相当长。
  • 3)我会谈谈在前端使用线程。

在前端使用线程没有意义。如上所述,您的Web服务器具有已定义的处理模型,它旨在与该模型一起扩展,创建用户线程,因为Web请求会中断该模型。即使用户代码创建了合理数量的线程,例如8,如果同时出现100个客户端,您将要求硬件同时执行800个线程。

这显然是一个坏主意!

场景#2

  • 1)与#1.1相同的答案,它是处理多个客户端的服务器的处理模型。
  • 2)在两种情况下与问题1的答案相同。
  • 3)这完全是一个意见问题。

在两种情况下,您似乎遇到的问题基本相同。

建议

不要做任何比它必须更复杂的事情;在这两种情况下,问题是你的接收服务器端代码的响应速度比想要的慢。

如果您有许多HTTP请求要处理请求,您的代码是I / O绑定的,不要直接进行多处理或多线程,请尝试非阻塞I / O首先,这更简单,更易于访问,更适合用PHP扩展。

例如,在您拥有受CPU限制的代码的情况下,您已解决了I / O问题,并且正在使用非阻塞I / O发出所有请求,但是一旦下载了数据,就需要相当多的要使用的处理。然后您可能会考虑使用多个进程或线程。

无论发生什么,你都不应该在前端使用多线程,你要做的就是隔离那些需要多线程的应用程序部分,并使用一些理智的RPC与这个孤立的子应用程序进行通信。 / p>