如果两个用户执行相同的php文件,它是并行还是顺序执行?例如:
如果我有一个数据库数据只有一列 id ,下面的代码可能会为两个不同的用户产生相同的结果吗?
1. $db=startConnection();
2. $query="SELECT id FROM data";
3. $result=$db->query($query)or die($db->error);
4. $zeile=mysqli_fetch_row($result);
5. $number=$zeile['id'];
6. $newnumber=$number+1;
7. echo $number;
8. $update = "UPDATE data Set id = '$newnumber' WHERE id = '$number'";
9. $db->query($query)or die($db->error);
10. mysqli_close($db);
如果没有并行执行,是否意味着当100个人正在加载一个加载时间为1秒的php文件时,其中一个必须等待99秒?
编辑:在评论中声明我可以搞砸我的数据库,我想这就是它可能搞砸了:
用户A执行1.-7中的文件。此时用户B从1.-7执行文件。然后A加载8.-10。和B加载8.-10。在这种情况下,两个用户在屏幕上的编号都相同。
现在让我们举几个例子:
1. $db=startConnection();
2. $query=" INSERT INTO data VALUES ()";
3. $result=$db->query($query)or die($db->error);
4. echo $db->insert_id;
5. mysqli_close($db);
让我们说A执行1.-3中的文件。此时用户B从1.-5执行文件,之后用户A从4.-5加载文件。我想在这种情况下,两个屏幕上的数字都是相同的吗?交易会阻止两种情况吗?
答案 0 :(得分:4)
你可以说php文件是并行执行的(大多数情况下是这样的,但这取决于web服务器)。
是的,以下代码可能会为两个不同的用户产生相同的结果。
1)如果您使用的是MySQL,则可以使用和“SELECT ... UPDATE FOR”事务来避免这种可能性。只是使用交易无济于事!
2)确保您使用InnoDB或任何其他支持事务的数据库引擎。例如,MyISAM 不支持支持交易。如果在数据库中启用了任何形式的快照以处理读取锁定的记录,也会出现问题。
3)使用“SELECT ... UPDATE FOR”的例子:
$db = startConnection();
// Start transaction
$db->query("START TRANSACTION") or die($db->error);
// Your SELECT request but with "FOR UPDATE" lock
$query = "SELECT id FROM data FOR UPDATE";
$result = $db->query($query);
// Rollback changes if there is error
if (!$result)
{
mysql_query("ROLLBACK");
die($db->error);
}
$zeile = mysqli_fetch_row($result);
$number = $zeile['id'];
$newnumber = $number + 1;
echo $number;
$update = "UPDATE data Set id = '$newnumber' WHERE id = '$number'";
$result = $db->query($query);
// Rollback changes if there is error
if (!$result)
{
mysql_query("ROLLBACK");
die($db->error);
}
// Commit changes in database after requests sucessfully executed
mysql_query("COMMIT");
mysqli_close($db);
只是事务才会锁定写入。您可以通过在两个单独的终端窗口中运行两个mysql控制台客户端来测试示例。我这样做了,这就是它的运作方式。
我们有客户端#1和客户端#2并行执行。
client#1: BEGIN
client#2: BEGIN
client#1: SELECT id FROM data // fetched id = 3
client#2: SELECT id FROM data // fetched id = 3
client#1: UPDATE data Set id = 4 WHERE id = 3
client#2: UPDATE data Set id = 4 WHERE id = 3
client#1: COMMIT
client#2: COMMIT
两个客户端都获取了相同的id(3)。
client#1: BEGIN
client#2: BEGIN
client#1: SELECT id FROM data FOR UPDATE // fetched id = 3
client#2: SELECT id FROM data FOR UPDATE // here! client#2 will wait for end of transaction started by client#1
client#1: UPDATE data Set id = 4 WHERE id = 3
client#1: COMMIT
client#2: client#1 ended transaction and client#2 fetched id = 4
client#1: UPDATE data Set id = 5 WHERE id = 4
client#2: COMMIT
“SELECT ... FOR UPDATE”仅对使用“SELECT ... FOR UPDATE”的客户端执行read-lock。这很好,因为这意味着这样的读锁定不会影响标准的“SELECT”请求而没有“FOR UPDATE”。
MySQL documentation: "SELECT ... FOR UPDATE" and other read-locks
答案 1 :(得分:3)
您的部分问题是关于PHP并行或顺序运行。由于我已经阅读了有关该主题的所有内容和相反内容,因此我决定自己进行测试。
现场测试:
在运行PHP 5.5 w / Apache 2的LAMP堆栈上,我创建了一个非常昂贵的循环脚本:
function fibo($n)
{
return ($n > 1) ? fibo($n - 1) + fibo($n - 2) : 1;
}
$start = microtime(true);
print "result: ".fibo(38);
$end = microtime(true);
print " - took ".round(($end - $start), 3).' s';
运行1个脚本的结果:
结果:63245986 - 耗时19.871秒
在两个不同的浏览器窗口中同时运行2个脚本的结果:
结果:63245986 - 耗时20.753秒
结果:63245986 - 耗时20.847秒
在三个不同的浏览器窗口中同时运行3个脚本的结果:
结果:63245986 - 花了26.172秒
结果:63245986 - 花了28.302秒
结果:63245986 - 耗时28.422秒
运行2个脚本实例时的CPU使用情况:
运行3个脚本实例时的CPU使用率:
在PHP脚本中,你不能轻易使用多线程(尽管可能),Apache可以从具有多个内核的服务器中获益,以便分配负载。
因此,如果您的1秒脚本同时由100个用户运行,那么如果您有100个CPU核心,那么第100个用户几乎不会注意到任何内容。如果你有8个CPU核心(这是更常见的),那么第100个用户将理论上必须等待100 / 8 = 12.5
秒之后开始他的脚本实例。实际上,当“基准”提供证据时,当其他线程在其他核心上同时运行时,每个线程的性能都会降低。所以它可能会更多。但不是100秒。