PHP利用文件锁处理高并发

在解决高并发的情景下,我们除了使用Redis缓存来实现外,利用文件锁也是一种常常使用的方法,下面介绍PHP是如何使用flock()函数对文件进行加锁,从而解决高并发的情况。

1.flock函数的介绍
flock有三个参数分别是:(file,lock,block)
  file:已经打开的文件
  lock:锁的类型
    LOCK_SH:共享锁(读锁)
    LOCK_EX:独占锁定(排它锁,写锁)
    LOCK_UN:解锁
    LOCK_NB:如果希望在文件锁定时阻塞进程,那么需要加上该参数
  block:设置为true的时候,锁定文件时,会阻止其他进程
  
2.使用例子

例1:a使用独占锁写文件,b读取文件,阻塞

a.php

<?php  
$file = 'test.txt';  
$fp = fopen($file, 'w');  
if(flock($fp, LOCK_EX)){            // 取得独占锁  
    fwrite($fp, "Hello World\r\n"); // 写入数据  
    sleep(10);                      // sleep 10秒,文件被锁定  
    fwrite($fp, "Hello PHP\r\n");   // 写入数据  
    flock($fp, LOCK_UN);            // 解锁  
}  
fclose($fp);  
?>  

b.php

<?php  
$file = 'test.txt';  
$fp = fopen($file, 'r');  
if(flock($fp, LOCK_SH)){ // 取得贡献锁  
    while(!feof($fp)){  
        echo fread($fp, 100);  
    }  
    flock($fp, LOCK_UN);  
}  
fclose($fp);  
?>  

先执行a.php,然后执行b.php
a取得独占锁,b只能等待,等a执行完解除锁定后才能执行b,阻塞

例2:a,b都使用共享锁,不阻塞

a.php

<?php  
$file = 'test.txt';  
$fp = fopen($file, 'r');  
if(flock($fp, LOCK_SH)){ // 取得共享锁  
    sleep(10);           // sleep 10秒  
    while(!feof($fp)){  
        echo fread($fp, 100);  
    }  
    flock($fp, LOCK_UN);  
}   
fclose($fp);  
?>  

b.php

<?php  
$file = 'test.txt';  
$fp = fopen($file, 'r');  
if(flock($fp, LOCK_SH)){ // 取得共享锁  
    while(!feof($fp)){  
        echo fread($fp, 100);  
    }  
    flock($fp, LOCK_UN);  
}   
fclose($fp);  
?>  

先执行a.php,然后执行b.php
b不需要等待a执行完就能输出文件内容,非阻塞

例3:a,b都使用独占锁写文件,阻塞

a.php

<?php  
$file = 'test.txt';  
$fp = fopen($file, 'a');  
if(flock($fp, LOCK_EX)){            // 取得独占锁  
    fwrite($fp, "Hello World\r\n"); // 写入数据  
    sleep(10);                      // sleep 10秒,文件被锁定  
    fwrite($fp, "Hello PHP\r\n");   // 写入数据  
    flock($fp, LOCK_UN);            // 解锁  
}   
fclose($fp);  
?>  

b.php

<?php  
$file = 'test.txt';  
$fp = fopen($file, 'a');  
if(flock($fp, LOCK_EX)){                    // 取得独占锁  
    fwrite($fp, "How Are You\r\n");         // 写入数据  
    fwrite($fp, "Show Me The Money\r\n");   // 写入数据  
    flock($fp, LOCK_UN);                    // 解锁  
}  
fclose($fp);  
?>  

先执行a.php,然后执行b.php
b需要等待a执行完,才能写入数据,阻塞

例4:LOCK_NB 锁定时不阻塞,不等待

a.php

<?php  
$file = 'test.txt';  
  
$fp = fopen($file, 'a');  
  
if(flock($fp, LOCK_EX)){            // 取得独占锁  
    fwrite($fp, "Hello World\r\n"); // 写入数据  
    sleep(10);                      // sleep 10秒,文件被锁定  
    fwrite($fp, "Hello PHP\r\n");   // 写入数据  
    flock($fp, LOCK_UN);            // 解锁  
}  
  
fclose($fp);  
?>  

b.php

<?php  
$file = 'test.txt';  
  
$fp = fopen($file, 'a');  
  
if(flock($fp, LOCK_EX|LOCK_NB)){            // 取得独占锁  
    fwrite($fp, "How Are You\r\n");         // 写入数据  
    fwrite($fp, "Show Me The Money\r\n");   // 写入数据  
    flock($fp, LOCK_UN);                    // 解锁  
}else{  
    echo 'file locked';  
}  
fclose($fp);  
?>  

先执行a.php,然后执行b.php
b取不到独占锁,不需要等待a执行完,而是直接返回取不到锁提示,非阻塞

总结:
flock() 允许执行一个简单的可以在任何平台中使用的读取/写入模型
使用共享锁LOCK_SH,如果是读取,不需要等待,但如果是写入,需要等待读取完成。
使用独占锁LOCK_EX,无论写入/读取都需要等待。

LOCK_UN,无论使用共享/读占锁,使用完后需要解锁。
LOCK_NB,当被锁定时,不阻塞,而是提示锁定。

发布了31 篇原创文章 · 获赞 27 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Hjingeng/article/details/104036436