php文件是并行执行还是顺序执行?

时间:2014-02-08 18:43:13

标签: php

如果两个用户执行相同的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加载文件。我想在这种情况下,两个屏幕上的数字都是相同的吗?交易会阻止两种情况吗?

2 个答案:

答案 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并行执行。

示例#1。没有“SELECT ... FOR UPDATE”:

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)。

示例#2。使用“SELECT ... FOR UPDATE”:

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使用情况:

enter image description here

运行3个脚本实例时的CPU使用率:

enter image description here

所以,它是平行的!

在PHP脚本中,你不能轻易使用多线程(尽管可能),Apache可以从具有多个内核的服务器中获益,以便分配负载。

因此,如果您的1秒脚本同时由100个用户运行,那么如果您有100个CPU核心,那么第100个用户几乎不会注意到任何内容。如果你有8个CPU核心(这是更常见的),那么第100个用户将理论上必须等待100 / 8 = 12.5秒之后开始他的脚本实例。实际上,当“基准”提供证据时,当其他线程在其他核心上同时运行时,每个线程的性能都会降低。所以它可能会更多。但不是100秒。