PHP是逐个请求还是同时请求?

3

我有关于PHP和请求如何在后台工作的一些问题。

1) 假设我编写了我的PHP应用并将其上传到服务器。现在有一个函数,如果用户访问执行该函数的路由,某些操作会发生。

问题是:如果一个用户发出请求,另一个用户也发出请求,第二个用户是否必须等待第一个用户的请求结束?(通过“请求结束”,我指直到我编写的函数完全执行)。这是正确的猜测还是无论执行哪个函数都没有关系。在请求未完成之前,第二个请求永远不会启动?

2) 我有我的PHP应用程序。假设两个人同时向数据库写入数据(不是写入,而是更新)。假设我使用了负载均衡器。如果一个用户向balancer1发出请求,另一个用户向balancer2发出请求,我想要做的是,如果第一个用户的调用更新数据库,则第二个用户的请求必须立即停止(它不应该被更新)。

场景是我在我的数据库中拥有JWT令牌,用于对第三方工具进行请求。它的过期时间为1小时。假设已经过去了1小时。如果一个用户发出更新令牌的调用,并且在途中第二个用户也发出更新令牌的调用,那么会发生的是第二个用户将更新令牌,并且第一个用户的令牌将无效,这是不好的。

3个回答

3

PHP可以同时处理多个请求,但是如果用户的PHP会话被第一个请求锁定,来自同一用户的请求将逐个处理。当会话关闭后,第二个请求将被处理。

例如,如果您在一个浏览器标签中运行带有sleep(30)的PHP脚本:

<?
session_start();

sleep(30);

还有另一个选项卡中的脚本:

<?
session_start();

echo 'hello';

第二个脚本直到第一个脚本执行完毕后才会被执行。
需要注意这种行为,因为会话在几乎每个应用程序中都被使用。

对于第二个问题,我不确定。 - Nikolai Kiselev
@NikaKhurashvili 我添加了一个测试,你可以用来验证它。 - Nikolai Kiselev

0
  1. 如果您有一个由控制器函数提供服务的路由,每个请求都会有一个单独的控制器实例。例如:用户A和用户B请求相同的路由laravel.com/stackoverflow,控制器将准备响应每个请求,而不管同时有多少用户请求。您可以将其视为任何服务进程的原则。例如,Laravel在PHP上运行。因此,每次我们需要PHP处理任何脚本时,PHP都会创建进程线程。类似地,Laravel为每个请求实例化控制器。
  2. 对于发送多个请求的同一用户,它仍将像第1点一样进行处理。
  3. 如果您想逐个处理特定请求,您可以排队作业。例如,假设您想处理付款。您有5个请求正在进行。因此,控制器将同时处理所有请求,但控制器函数可以调度排队作业,并且这些作业将逐个处理。
  4. 考虑两个人尝试请求具有DB更新功能的相同路由,您可以阅读一个关于乐观锁定和悲观锁定的好文章here

谢谢。@尼古拉下面也回答了,他说:“但是 PHP 会逐个执行同一用户的请求。这是因为 PHP 锁定用户的会话文件直到请求完成。除非会话已解锁,否则不会执行另一个请求。”那你对此有什么看法?你说的相反。 - Nika Kurashvili
我不相信 Laravel 或者基本的 PHP 有任何机制来锁定用户的同时请求。测试的简单方法是打开一个 Laravel URL 或者一个可以通过 Web 打开的简单的 PHP 脚本,并在同时多个标签页中打开它。 - Mihir Bhende
总的来说,@MihirBhende是正确的,PHP将同时执行来自同一用户的请求。但是,如果会话已打开,PHP确实有一种锁定请求的机制。请查看文档http://us.php.net/manual/en/function.session-write-close.php。我会更新我的答案。 - Nikolai Kiselev

0

我应该投票关闭这个问题——它太广泛了……但我会试着回答一下。

如果请求依赖于只能执行一个任务的资源,那么它们就不能“同时”运行。你可能只有一个CPU核心或一个磁盘,但在HTTP请求的级别上(在没有代码应用互斥锁的情况下),它们将看起来是同时运行的——这就是多任务处理的全部意义。执行线程通常会因等待其他事件而延迟,在此时操作系统任务调度程序将检查是否有其他任务等待运行。你可以轻松地自己测试这一点:

 <?php

 $started=time();
 sleep(20);
 print "Ran for " . (time() - $started) " seconds";

(尝试在同一时间内在不同的浏览器窗口中访问此内容-或在同一窗口的2个iframe中)

与此进行比较:

 <?php

 $started=time();
 $fh=fopen("/tmp/concurency_test", "w");
 flock($fh, LOCK_EX);
 sleep(20);
 flock($fh, LOCK_UN);
 print "Ran for " . (time() - $started) " seconds";

这也展示了为什么您不应该在服务器上使用平面文件来存储数据的原因之一。请注意,PHP中的默认会话处理程序在脚本打开会话数据期间使用基于文件的锁定。

数据库采用各种策略来避免回到单个操作排队 - 最常见的是版本控制。但这并没有解决您描述的问题:两个客户端永远不应该使用相同的会话令牌 - 这就是为什么会话令牌与凭据在良好设计的系统中是分离的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接