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 分页原理分析,大家可以看看
Dec 21 PHP
PHP中strtotime函数使用方法分享
Jan 10 PHP
在项目中寻找代码的坏命名
Jul 14 PHP
Thinkphp模板中使用自定义函数的方法
Sep 23 PHP
thinkphp的CURD和查询方式介绍
Dec 19 PHP
ECMall支持SSL连接邮件服务器的配置方法详解
May 19 PHP
PHP中的gzcompress、gzdeflate、gzencode函数详解
Jul 29 PHP
php查找指定目录下指定大小文件的方法
Nov 28 PHP
php实现cookie加密的方法
Mar 10 PHP
PHP获取photoshop写入图片文字信息的方法
Mar 31 PHP
PHP实现ASCII码与字符串相互转换的方法
Apr 29 PHP
php 使用curl模拟ip和来源进行访问的实现方法
May 02 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
天使彦史上最神还原,性别曝光的那一刻,百万网友恋爱了
2020/03/02 国漫
国王的咖啡这么大来头,名字的由来是什么
2021/03/03 咖啡文化
关于初学PHP时的知识积累总结
2013/06/07 PHP
简单说说PHP优化那些事(经验分享)
2014/11/27 PHP
PHP通过引用传递参数用法分析
2016/12/01 PHP
php面试中关于面向对象的相关问题
2019/02/13 PHP
php字符串截取函数mb_substr用法实例分析
2019/06/25 PHP
js 实现复制到粘贴板的功能代码
2010/05/13 Javascript
基于Jquery实现的一个图片滚动切换
2012/06/21 Javascript
node.js超时timeout详解
2014/11/26 Javascript
对JavaScript中this指针的新理解分享
2015/01/31 Javascript
Jquery实现仿腾讯娱乐频道焦点图(幻灯片)特效
2015/03/06 Javascript
javascript无刷新评论实现方法
2015/05/13 Javascript
vuex实现简易计数器
2016/10/27 Javascript
jQuery获取this当前对象子元素对象的方法
2016/11/29 Javascript
JS实现拖拽的方法分析
2016/12/20 Javascript
JS实现一个简单的日历
2017/02/22 Javascript
JavaScript无阻塞加载和defer、async详解
2017/02/26 Javascript
NodeJS自定义模块写法(详解)
2017/06/27 NodeJs
利用百度echarts实现图表功能简单入门示例【附源码下载】
2019/06/10 Javascript
详解ng-alain动态表单SF表单项设置必填和正则校验
2019/06/11 Javascript
[02:53]DOTA2亚洲邀请赛 NewBee战队巡礼
2015/02/03 DOTA
python操作excel文件并输出txt文件的实例
2018/07/10 Python
在pycharm中实现删除bookmark
2020/02/14 Python
pandas分组聚合详解
2020/04/10 Python
pytorch 查看cuda 版本方式
2020/06/23 Python
如果让你测试一台高速激光打印机,你都会进行哪些测试
2012/12/04 面试题
人力资源管理专业自荐书范文
2014/02/10 职场文书
自考毕业自我鉴定
2014/03/18 职场文书
社会治安综合治理管理责任书
2014/04/16 职场文书
道德之星事迹材料
2014/05/03 职场文书
优秀教师演讲稿
2014/05/06 职场文书
党员对照检查材料思想汇报(党的群众路线)
2014/09/24 职场文书
铁路安全反思材料
2014/12/24 职场文书
长城导游词300字
2015/01/30 职场文书
教你快速开启Apache SkyWalking的自监控
2021/04/25 Servers