大家好,又见面了,我是你们的朋友全栈君。
一、文件锁是什么 ?
顾名思义,对文件上锁。
可以通过“进门”的实际情况来理解:
有多个人要通过一个大门到食堂里吃饭,但食堂只有一个座位。
食堂管理员A有点偷懒,不想等那么久,于是就告诉大家,中午都可以来食堂吃饭,但是要跑快点才行,只有一个座位,第一个到的人就可以在食堂吃饭,然后就会锁门,其他人看到门锁上了就哪来的回哪去吧,这就是非阻塞型文件锁;
食堂管理员B不希望让人吃不上饭,也不希望大家坐地上吃饭,所以就通知大家在门外排队,一个人进来吃完后,下一个人才允许进来。所以当第一个人进大门后,管理员B就把大门锁上,等第一个人吃完后,再解锁打开大门让第二个人进来,这就是阻塞型文件锁。
比喻不是完全正确,但是那么个意思,凑合着理解一下。
二、文件锁有什么作用 ?
锁机制之所以存在是因为并发导致的资源竞争,为了确保操作的有效性和完整性,可以通过锁机制将并发状态转换成串行状态。作为锁机制中的一种,PHP的文件锁也是为了应对资源竞争。
假设一个应用场景,在存在较大并发的情况下,通过fwrite向文件尾部多次有序的写入数据,不加锁的情况下会发生什么?多次有序的写入操作相当于一个事务,我们此时需要保证这个事务的完整性,所以加锁具有一定的必要性。
三、实际使用效果展示
1. 不使用文件锁
代码语言:javascript复制<?php
// 1. 打开文件
$lock_file = 'temp.lock';
$fp = fopen($lock_file, 'a ');
// 2. 打点
fwrite($fp, "打点:".date("Y-m-d H:i:s",time())."n");
// 3. 延迟1秒
sleep(1);
// 4. 关闭文件
fclose($fp);
使用ab压力测试器执行文件十次,查看temp.lock:
2. 使用非阻塞型文件锁
代码语言:javascript复制<?php
// 1. 打开文件
$p_file = "temp.lock";
$fp = fopen($p_file, 'a ');
// 2. 判断是否已存在文件锁,存在(上锁失败)则退出
if (!flock($fp, LOCK_EX LOCK_NB)) {
exit;
}
// 3. 上锁
flock($fp, LOCK_EX LOCK_NB);
// 4. 给文件打点
fwrite($fp, "打点:".date("Y-m-d H:i:s",time())."n");
// 5. 延迟1秒
sleep(1);
// 6. 解锁文件
flock($fp, LOCK_UN);
// 7. 关闭文件
fclose($fp);
使用ab压力测试器执行文件十次,查看temp.lock:
3. 使用阻塞型文件锁
代码语言:javascript复制<?php
// 1. 打开文件
$lock_file = 'temp.lock';
$fp = fopen($lock_file, 'a ');
// 2. 判断是否已经上锁
if (!flock($fp, LOCK_EX)) {
unlink($lock_file);
exit;
}
// 3. 打点
fwrite($fp, "打点:".date("Y-m-d H:i:s",time())."n");
// 4. 延迟1秒
sleep(1);
// 5. 解开文件锁
flock($fp,LOCK_UN);
// 6. 关闭文件
fclose($fp);
使用ab压力测试器执行文件十次,查看temp.lock:
四、总结
通过上面三个简单代码示范,可以很清楚看到使用文件锁和不使用文件锁的区别,以及非阻塞型文件锁和阻塞型文件锁的区别:
不使用文件锁时,十个并发访问,同时执行插入,在这种情况下不但不能保持执行序列,还会丢失3条请求; 使用非阻塞型文件锁时,又只能有一条请求能通过,其他请求在并发同时访问到文件已经加锁,只好断开请求; 阻塞型文件锁的结果优势很明显,得到十条数据,并且按照1秒的顺序插入,这也是我们想得到的效果。
所以,在并发量较小的一些场景,可以考虑使用阻塞型文件锁,但是如果只是要得到一条有效数据,其他的都可以忽略的话,那也可以使用非阻塞型文件锁。
注意:文件锁的使用会增加服务器 I/O 的消耗,因此还是尽量少用,访问量较小、并发量小的情况下,可以考虑使用文件锁。如果涉及数据库操作顺序的话,可以使用mysql锁,但如果并发量太大的话,就要考虑缓存锁,利用缓存的时间来进行加锁控制。简单提提,后面有时间再做专门的整理。
不熟悉ab压力测试工具的朋友请参考我这篇文章:ab压力测试工具
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/153477.html原文链接:https://javaforall.cn