PHP 一个接一个或同时请求
PHP requests one by one or simultaneously
我有一些关于 PHP 以及请求如何在幕后工作的问题。
1) 假设我编写了 PHP 应用程序并将其上传到服务器。现在有一个我写的函数,如果用户转到执行该函数的那条路线,就会发生一些事情。
问题是:如果一个用户发出请求,另一个用户也发出请求,第二个用户是否必须等到第一个用户的请求完成? (说请求已完成,我的意思是直到我编写的函数执行到最后)。这是正确的猜测还是执行哪个函数无关紧要。在请求未完成之前,第二个请求永远不会开始?
2) 我有我的 PHP 申请。想象一下,两个人同时发出请求,将数据写入数据库(不是写入,而是更新)。假设我使用了负载均衡器。如果一个用户向 balancer1 发出请求而另一个用户向 balancer2 发出请求,我想做的是如果第一个用户的调用更新了数据库,第二个用户的请求必须立即停止(不应该更新)。
场景是我的数据库中有 jwt 令牌,用于在第三方工具上执行请求。它的有效期为 1 小时。假设 1 小时过去了。如果一个用户调用更新令牌,而第二个用户也调用更新令牌,那么第二个用户将更新令牌,而第一个用户的令牌将无效,这很糟糕。
PHP 将同时处理请求。处理一个请求不会为 不同的 用户锁定另一个请求。但是 PHP 可以一个接一个地执行来自 同一个 用户的请求,如果 PHP 会话被第一个请求锁定。第二个请求将在会话结束时进行。
尝试在第一个浏览器选项卡中使用 sleep(30)
运行 PHP 脚本:
<?
session_start();
sleep(30);
另一个浏览器选项卡中的另一个脚本:
<?
session_start();
echo 'hello';
第一个脚本完成后才会执行脚本 #2。
这很重要,因为您在每个应用程序中都使用会话。
- 如果您有一个由控制器函数提供服务的路由,则对于每个请求都有一个单独的控制器实例。例如:用户A和用户B请求相同的路由
laravel.com/Whosebug
,控制器准备响应每个请求,与多少用户同时请求无关。您可以将相似视为任何服务的流程原则。例如,Laravel 在 PHP 上是 运行。因此,每次我们需要 PHP 来处理任何脚本时,PHP 都会创建进程线程。同样 Laravel 为每个请求实例化控制器。
- 对于同一用户发送多个请求,仍将按第1点处理。
- 如果您想一一处理特定的请求,您可以queue 作业。例如,假设您要处理付款。您有 5 个请求正在发生。因此,控制器将同时处理所有请求,但控制器功能可以分派排队的作业,并逐个处理这些作业。
- 考虑到两个人尝试请求具有数据库更新功能的同一条路由,您可以阅读一篇关于乐观和悲观锁定的好文章here。
我应该投票结束这个 - 它太宽泛了....但我会试一试。
如果请求依赖于一次只能执行一项任务的资源,则它们不能"run"并发。很有可能您有一个 CPU 核心或一个磁盘 - 但是在 HTTP 请求级别(在没有应用互斥锁定的代码的情况下)它们将显示为 运行同时 - 这就是多任务处理的意义所在。执行线程通常会延迟等待其他事情发生,此时 OS 任务调度程序将检查是否有任何其他任务等待 运行。您可以自己轻松测试:
<?php
$started=time();
sleep(20);
print "Ran for " . (time() - $started) " seconds";
(尝试大约在同一时间在不同的浏览器 windows 中访问它 - 或者在同一个 window 上的 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 中的默认会话处理程序在脚本打开会话数据期间使用基于文件的锁定。
数据库采用多种策略来避免恢复到单一操作排队——最常见的是版本控制。这不能解决您描述的问题:2 个客户端永远不应该使用相同的会话令牌 - 这就是会话令牌与设计良好的系统中的凭据分开的原因。
我有一些关于 PHP 以及请求如何在幕后工作的问题。
1) 假设我编写了 PHP 应用程序并将其上传到服务器。现在有一个我写的函数,如果用户转到执行该函数的那条路线,就会发生一些事情。
问题是:如果一个用户发出请求,另一个用户也发出请求,第二个用户是否必须等到第一个用户的请求完成? (说请求已完成,我的意思是直到我编写的函数执行到最后)。这是正确的猜测还是执行哪个函数无关紧要。在请求未完成之前,第二个请求永远不会开始?
2) 我有我的 PHP 申请。想象一下,两个人同时发出请求,将数据写入数据库(不是写入,而是更新)。假设我使用了负载均衡器。如果一个用户向 balancer1 发出请求而另一个用户向 balancer2 发出请求,我想做的是如果第一个用户的调用更新了数据库,第二个用户的请求必须立即停止(不应该更新)。
场景是我的数据库中有 jwt 令牌,用于在第三方工具上执行请求。它的有效期为 1 小时。假设 1 小时过去了。如果一个用户调用更新令牌,而第二个用户也调用更新令牌,那么第二个用户将更新令牌,而第一个用户的令牌将无效,这很糟糕。
PHP 将同时处理请求。处理一个请求不会为 不同的 用户锁定另一个请求。但是 PHP 可以一个接一个地执行来自 同一个 用户的请求,如果 PHP 会话被第一个请求锁定。第二个请求将在会话结束时进行。
尝试在第一个浏览器选项卡中使用 sleep(30)
运行 PHP 脚本:
<?
session_start();
sleep(30);
另一个浏览器选项卡中的另一个脚本:
<?
session_start();
echo 'hello';
第一个脚本完成后才会执行脚本 #2。
这很重要,因为您在每个应用程序中都使用会话。
- 如果您有一个由控制器函数提供服务的路由,则对于每个请求都有一个单独的控制器实例。例如:用户A和用户B请求相同的路由
laravel.com/Whosebug
,控制器准备响应每个请求,与多少用户同时请求无关。您可以将相似视为任何服务的流程原则。例如,Laravel 在 PHP 上是 运行。因此,每次我们需要 PHP 来处理任何脚本时,PHP 都会创建进程线程。同样 Laravel 为每个请求实例化控制器。 - 对于同一用户发送多个请求,仍将按第1点处理。
- 如果您想一一处理特定的请求,您可以queue 作业。例如,假设您要处理付款。您有 5 个请求正在发生。因此,控制器将同时处理所有请求,但控制器功能可以分派排队的作业,并逐个处理这些作业。
- 考虑到两个人尝试请求具有数据库更新功能的同一条路由,您可以阅读一篇关于乐观和悲观锁定的好文章here。
我应该投票结束这个 - 它太宽泛了....但我会试一试。
如果请求依赖于一次只能执行一项任务的资源,则它们不能"run"并发。很有可能您有一个 CPU 核心或一个磁盘 - 但是在 HTTP 请求级别(在没有应用互斥锁定的代码的情况下)它们将显示为 运行同时 - 这就是多任务处理的意义所在。执行线程通常会延迟等待其他事情发生,此时 OS 任务调度程序将检查是否有任何其他任务等待 运行。您可以自己轻松测试:
<?php
$started=time();
sleep(20);
print "Ran for " . (time() - $started) " seconds";
(尝试大约在同一时间在不同的浏览器 windows 中访问它 - 或者在同一个 window 上的 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 中的默认会话处理程序在脚本打开会话数据期间使用基于文件的锁定。
数据库采用多种策略来避免恢复到单一操作排队——最常见的是版本控制。这不能解决您描述的问题:2 个客户端永远不应该使用相同的会话令牌 - 这就是会话令牌与设计良好的系统中的凭据分开的原因。