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多线程抓取网页实现代码
Jul 22 PHP
PHP MemCached高级缓存配置图文教程
Aug 05 PHP
php图像处理函数大全(推荐收藏)
Jul 11 PHP
ThinkPHP CURD方法之data方法详解
Jun 18 PHP
php的mkdir()函数创建文件夹比较安全的权限设置方法
Jul 28 PHP
PHP面向对象程序设计之类常量用法实例
Aug 20 PHP
PHP实现的QQ空间g_tk加密算法
Jul 09 PHP
PHP简单实现断点续传下载的方法
Sep 25 PHP
PHP生成加减算法方式的验证码实例
Mar 12 PHP
thinkphp5使用无限极分类
Feb 18 PHP
PHP二维索引数组的遍历实例分析【2种方式】
Jun 24 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
Feb 27 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网站的几个实用要点
2014/12/30 PHP
html下载本地
2006/06/19 Javascript
jquery.validate使用攻略 第三部
2010/07/01 Javascript
jquery动画2.元素坐标动画效果(创建一个图片走廊)
2012/08/24 Javascript
js根据给定的日期计算当月有多少天实现思路及代码
2013/02/25 Javascript
不使用浏览器运行javascript代码的方法
2013/07/24 Javascript
Jquery选中或取消radio示例
2013/09/29 Javascript
解析页面加载与js函数的执行 onload or ready
2013/12/12 Javascript
原生javascript实现获取指定元素下所有后代元素的方法
2014/10/28 Javascript
JavaScript获取两个数组交集的方法
2015/06/09 Javascript
jQuery网页选项卡插件rTabs用法实例分析
2015/08/26 Javascript
超赞的jQuery图片滑块动画特效代码汇总
2016/01/25 Javascript
jQuery实现的导航动画效果(附demo源码)
2016/04/01 Javascript
基于AngularJS前端云组件最佳实践
2016/10/20 Javascript
html中鼠标滚轮事件onmousewheel的处理方法
2016/11/11 Javascript
Javascript中JSON数据分组优化实践及JS操作JSON总结
2017/12/22 Javascript
webpack引入eslint配置详解
2018/01/22 Javascript
webpack+vue+express(hot)热启动调试简单配置方法
2018/09/19 Javascript
nodejs require js文件入口,在package.json中指定默认入口main方法
2018/10/10 NodeJs
Python标准库内置函数complex介绍
2014/11/25 Python
python中print的不换行即时输出的快速解决方法
2016/07/20 Python
Python 装饰器深入理解
2017/03/16 Python
django反向解析和正向解析的方式
2018/06/05 Python
pandas带有重复索引操作方法
2018/06/08 Python
python实现诗歌游戏(类继承)
2019/02/26 Python
详解Django 时间与时区设置问题
2019/07/23 Python
pyinstaller打包找不到文件的问题解决
2020/04/15 Python
Sandro法国官网:法国成衣品牌
2019/08/28 全球购物
大学自主招生推荐信
2014/05/10 职场文书
工资收入证明样本(5篇)
2014/09/16 职场文书
2015年组织部工作总结
2015/04/03 职场文书
观看禁毒宣传片后的感想
2015/08/11 职场文书
2016教师暑期培训学习心得体会
2016/01/09 职场文书
2019终止劳动合同协议书最新范本!
2019/07/09 职场文书
简单介绍Python的第三方库yaml
2021/06/18 Python
Shell脚本一键安装Nginx服务自定义Nginx版本
2022/03/20 Servers