PHP 进程锁定问题分析研究


Posted in PHP onNovember 24, 2009

1. 区分读锁定 和 写 锁定。
如果每次都使用 写锁定,那么连多个进程读取一个文件也要排队,这样的效率肯定不行。
2. 区分 阻塞 与 非 阻塞模式。
一般来说,如果一个进程在写一个文件的时候,另外一个进程应该被阻塞,但是,很多时候,我们可以先干点别的事情,
然后再判断一下是否有其他人在写文件,如果没有,再加入数据,这样的效率更高。
3. 修复了 锁定文件在linux 上的bug,特别是 在 gfs 文件系统上的bug。
代码如下:

<?php 
class File_Lock 
{ 
private $name; 
private $handle; 
private $mode; 
function __construct($filename, $mode = 'a+b') 
{ 
global $php_errormsg; 
$this->name = $filename; 
$path = dirname($this->name); 
if ($path == '.' || !is_dir($path)) { 
global $config_file_lock_path; 
$this->name = str_replace(array("/", "\\"), array("_", "_"), $this->name); 
if ($config_file_lock_path == null) { 
$this->name = dirname(__FILE__) . "/lock/" . $this->name; 
} else { 
$this->name = $config_file_lock_path . "/" . $this->name; 
} 
} 
$this->mode = $mode; 
$this->handle = @fopen($this->name, $mode); 
if ($this->handle == false) { 
throw new Exception($php_errormsg); 
} 
} 
public function close() 
{ 
if ($this->handle !== null ) { 
@fclose($this->handle); 
$this->handle = null; 
} 
} 
public function __destruct() 
{ 
$this->close(); 
} 
public function lock($lockType, $nonBlockingLock = false) 
{ 
if ($nonBlockingLock) { 
return flock($this->handle, $lockType | LOCK_NB); 
} else { 
return flock($this->handle, $lockType); 
} 
} 
public function readLock() 
{ 
return $this->lock(LOCK_SH); 
} 
public function writeLock($wait = 0.1) 
{ 
$startTime = microtime(true); 
$canWrite = false; 
do { 
$canWrite = flock($this->handle, LOCK_EX); 
if(!$canWrite) { 
usleep(rand(10, 1000)); 
} 
} while ((!$canWrite) && ((microtime(true) - $startTime) < $wait)); 
} 
/** 
* if you want't to log the number under multi-thread system, 
* please open the lock, use a+ mod. then fopen the file will not 
* destroy the data. 
* 
* this function increment a delt value , and save to the file. 
* 
* @param int $delt 
* @return int 
*/ 
public function increment($delt = 1) 
{ 
$n = $this->get(); 
$n += $delt; 
$this->set($n); 
return $n; 
} 
public function get() 
{ 
fseek($this->handle, 0); 
return (int)fgets($this->handle); 
} 
public function set($value) 
{ 
ftruncate($this->handle, 0); 
return fwrite($this->handle, (string)$value); 
} 
public function unlock() 
{ 
if ($this->handle !== null ) { 
return flock($this->handle, LOCK_UN); 
} else { 
return true; 
} 
} 
} 
?>

测试代码:
<?php 
/** 
* 进行写锁定的测试 
* 打开线程1 
*/ 
require("file_lock.php"); 
$lock = new File_Lock(dirname(dirname(__FILE__)) . "/FileLock.lock"); 
/** 单个线程锁定的速度 1s 钟 3万次。 **/ 
/** 两个线程写,两万的数据 大概要 7s 钟*/ 
/** 一个线程写,一万的数据 大概要 3.9s 钟,居然两个文件同时写,要快一点*/ 
/** 不进行锁定,一个进程 写大概要 2.8s 钟,加锁是有代价的。 */ 
/** 不进行锁定,两个进程 分布不是很均匀,而且大多数都冲突 */ 
$lock->writeLock(); 
$lock->increment(); 
$lock->unlock(); 
while ($lock->get() < 2) { 
usleep(1000); 
} 
sleep(1); 
echo "begin to runing \n"; 
$t1 = microtime(true); 
for ($i = 0; $i < 10000; $i++) 
{ 
$lock->writeLock(); 
$lock->increment(1); 
$lock->unlock(); 
} 
$t2 = microtime(true) - $t1; 
echo $t2; 
?>

我增加了一个 increment 的函数,可以实现简单的线程同步,让两个进程同时执行某段代码,当然,这个有一定的误差
这里的误差是 0.001s。
把这个类简单的用到 前面的memcache 消息队列中就可以实现 线程安全的消息队列。
PHP 相关文章推荐
隐藏你的.php文件的实现方法
Mar 19 PHP
Blitz templates 最快的PHP模板引擎
Apr 06 PHP
PHP 一个随机字符串生成代码
May 26 PHP
PHP中读写文件实现代码
Oct 20 PHP
解析PHP中如何将数组变量写入文件
Jun 06 PHP
php+mysql实现用户注册登陆的方法
Jan 03 PHP
PHP7+Nginx的配置与安装教程详解
May 10 PHP
PHP实现微信JS-SDK接口选择相册及拍照并上传的方法
Dec 05 PHP
php使用自定义函数实现汉字分割替换功能示例
Jan 30 PHP
浅谈Yii乐观锁的使用及原理
Jul 25 PHP
Laravel 登录后清空COOKIE的操作方法
Oct 14 PHP
PHP如何通过带尾指针的链表实现'队列'
Oct 22 PHP
PHP 递归效率分析
Nov 24 #PHP
PHP 单引号与双引号的区别
Nov 24 #PHP
PHP小程序自动提交到自助友情连接
Nov 24 #PHP
php 引用(&amp;)详解
Nov 20 #PHP
php+javascript的日历控件
Nov 19 #PHP
php与XML、XSLT、Mysql的结合运用实现代码
Nov 19 #PHP
php 静态变量的初始化
Nov 15 #PHP
You might like
PHP使用文件锁解决高并发问题示例
2018/03/29 PHP
禁止直接访问php文件代码分享
2020/05/05 PHP
PHP实现倒计时功能
2020/11/16 PHP
使用JQuery和s3captche实现一个水果名字的验证
2009/08/14 Javascript
setTimeout和setInterval的深入理解
2013/11/08 Javascript
利用js动态添加删除table行的示例代码
2013/12/16 Javascript
JS中自定义定时器让它在某一时刻执行
2014/09/02 Javascript
js实现文章文字大小字号功能完整实例
2014/11/01 Javascript
node中socket.io的事件使用详解
2014/12/15 Javascript
jQuery实现鼠标经过提示信息的地图热点效果
2015/04/26 Javascript
基于jQuery和Bootstrap框架实现仿知乎前端动态列表效果
2016/11/09 Javascript
js 中获取制定的cook信息实现方法
2016/11/19 Javascript
DropDownList控件绑定数据源的三种方法
2016/12/24 Javascript
原生js实现吸顶效果
2017/03/13 Javascript
jQuery实现base64前台加密解密功能详解
2017/08/29 jQuery
微信小程序实现的一键复制功能示例
2019/04/24 Javascript
node将geojson转shp返回给前端的实现方法
2019/05/29 Javascript
thinkjs微信中控之微信鉴权登陆的实现代码
2019/08/08 Javascript
TypeScript魔法堂之枚举的超实用手册
2020/10/29 Javascript
[02:08]DOTA2英雄基础教程 马格纳斯
2014/01/17 DOTA
[52:08]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第一局
2016/03/05 DOTA
编写Python脚本来获取mp3文件tag信息的教程
2015/05/04 Python
Python实现端口检测的方法
2018/07/24 Python
Python多线程原理与用法实例剖析
2019/01/22 Python
Django REST framework 分页的实现代码
2019/06/19 Python
pytorch 模型可视化的例子
2019/08/17 Python
python如何遍历指定路径下所有文件(按按照时间区间检索)
2020/09/14 Python
python 利用matplotlib在3D空间中绘制平面的案例
2021/02/06 Python
REISS英国官网:伦敦High Street最受欢迎品牌
2016/12/21 全球购物
预订全球最佳旅行体验:Viator
2018/03/30 全球购物
英国领先的豪华时尚家居网上商店:Amara
2019/08/12 全球购物
英语系本科生个人求职信
2013/09/21 职场文书
最新计算机专业自荐信
2013/10/16 职场文书
家长对孩子的感言
2014/03/10 职场文书
服务承诺书
2015/01/19 职场文书
css3带你实现3D转换效果
2022/02/24 HTML / CSS