服务器是否会同时处理两个或更多?

use*_*627 4 php

我在PHP中使用此代码将视图写入文本文件并仅增加数量.我的问题是:如果两个或更多人使用我的网站并运行PHP脚本会发生什么?服务器会处理吗?增加是否会保存到文件中?

这是我的代码(如果它有帮助):

<?php

    $clicks = file_get_contents("clicks.txt");
    $clicks++;

        $fp = fopen("clicks.txt", "w+");
        fwrite($fp, $clicks);
        fclose($fp);

//give the count to the user
echo "result: $clicks";

    ?>
Run Code Online (Sandbox Code Playgroud)

Eug*_*eck 6

首先:这不是我写点击计数器的方式.

也就是说,100个用户同时点击您的服务器(初始点击为0)可能会导致记录的数字为1..100,其中低(=错误)值突出.

  • 如果你想要计入一个文本文件,就像在@lanzz的答案中一样锁定并为主要的性能打击做好准备 - 你有效地序列化了这些请求.
  • 如果您想要计入任何文件,请考虑SQlite并为可管理的性能影响做好准备
  • 如果您只想计算,请考虑一个性能非常小的真正数据库

编辑:实现

我在文本文件SQLite和MySQL中为文件计数器创建了以下实现

请不要因为使用mysql_*()功能系列而激怒我- 因为总的来说,代码是有指导意义的,而不是高效的:在专注于手头的问题而不是周围的层面意义上是有益的.

反file.php:

<?php

//acquire file handle
$fd=fopen('counter.txt','c+b');
if (!$fd) die("Can't acquire file handle");

//lock the file - we must do this BEFORE reading, as not to read an outdated value
if (!flock($fd,LOCK_EX)) die("Can't lock file");

//read and sanitize the counter value
$counter=fgets($fd,10);
if ($counter===false) die("Can't read file");
if (!is_numeric($counter)) {
    flock($fd,LOCK_UN);
    die("Value in file '$counter' is not numeric");
}

//increase counter and reconvert to string
$counter++;
$counter="$counter";

//Write to file
if (!rewind($fd)) {
    flock($fd,LOCK_UN);
    die("Can't rewind file handle");
}
$num=fwrite($fd,$counter);
if ($num!=strlen($counter)) {
    flock($fd,LOCK_UN);
    die("Error writing file");
}

//Unlock the file and close file handle
flock($fd,LOCK_UN);
fclose($fd);

printf ("Counter is now %05d",$counter);
?>
Run Code Online (Sandbox Code Playgroud)

反sqlite.php:

<?php

//counter.sqlite3 was created with 
//CREATE TABLE counter (counter NUMERIC)
//INSERT INTO counter VALUES (0)

//Open database
$dsn='sqlite:'.dirname(__FILE__).'/counter.sqlite3';
$db=new PDO($dsn);
if (!$db) die("Can't open SQlite database via DBO");

//Make exclusive
$sql="BEGIN EXCLUSIVE TRANSACTION";
if ($db->exec($sql)===false) die("Error starting exclusive transaction");

//Update counter
$sql="UPDATE counter SET counter=counter+1";
if (!$db->exec($sql)) die("Error inserting into database");

//Read value
$sql="SELECT counter FROM counter";
$result=$db->query($sql);
if (!$result) die("Error querying database");
foreach ($result as $row) $counter=$row['counter'];

//Commit
$sql="COMMIT TRANSACTION";
if (!$db->exec($sql)) die("Error committing to database");

//Print result
printf("Counter is now %05d",$counter);

?>
Run Code Online (Sandbox Code Playgroud)

反mysql.php:

<?php

//mysql database was created with 
//CREATE TABLE counter (counter INT NOT NULL)
//INSERT INTO counter VALUES (0)

//Open database connection and select database 
$db=mysql_pconnect('127.0.0.1','redacted','redacted');
if (!$db) die("Can't open database");
if (!mysql_select_db('redacted', $db)) die("Can't select database");

//Update counter
$sql="UPDATE counter SET counter=counter+1";
$qry=mysql_query($sql,$db);
if (!$qry) die("Error updating database");

//Read value
$sql="SELECT counter FROM counter";
$qry=mysql_query($sql,$db);
if (!$qry) die("Error reading from database");
$counter=mysql_fetch_array($qry,MYSQL_ASSOC);
if (!$counter) die("Error reading result");

//Print result
printf("Counter is now %05d",$counter['counter']);

?>
Run Code Online (Sandbox Code Playgroud)

至于表现:我的立场得到了纠正.SQLite实现比其他两个慢100倍 - 这是因为我必须接受,除了START EXCLUSIVE TRANSACTION结束ab -n 1000 -c 50 http://127.0.0.1/stackoverflow/counter/counter-sqlite.php1000次点击计数的测试之外别无其他.

我对OP的建议是使用MySQL版本 - 它很快并且可以在操作系统崩溃时可靠地保存计数器.文件版本具有几乎相同的性能特征,但它很容易被操作系统崩溃破坏.