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下几种删除目录的方法总结
Aug 19 PHP
PHP iconv 函数转gb2312的bug解决方法
Oct 11 PHP
php 空格,换行,跳格使用说明
Dec 18 PHP
php 格式化数字的时候注意数字的范围
Apr 13 PHP
PHP获取表单textarea数据中的换行问题
Sep 10 PHP
基于PHP5魔术常量与魔术方法的详解
Jun 13 PHP
php字符串按照单词进行反转的方法
Mar 14 PHP
php实现可运算的验证码
Nov 10 PHP
详解在PHP的Yii框架中使用行为Behaviors的方法
Mar 18 PHP
PHP中抽象类和抽象方法概念与用法分析
May 24 PHP
php 数组处理函数extract详解及实例代码
Nov 23 PHP
CI框架(CodeIgniter)实现的数据库增删改查操作总结
May 23 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书写安全的脚本代码
2012/02/05 PHP
PHP和JavaScrip分别获取关联数组的键值示例代码
2013/09/16 PHP
php网页标题中文乱码的有效解决方法
2014/03/05 PHP
PHP的switch判断语句的“高级”用法详解
2014/10/01 PHP
PHP屏蔽过滤指定关键字的方法
2014/11/03 PHP
利用PHP函数计算中英文字符串长度的方法
2014/11/11 PHP
php利用smtp类实现电子邮件发送
2015/10/30 PHP
jQuery常用操作方法及常用函数总结
2014/06/19 Javascript
Javascript实现飞动广告效果的方法
2015/05/25 Javascript
JS判断页面是否出现滚动条的方法
2015/07/17 Javascript
JS排序方法(sort,bubble,select,insert)代码汇总
2016/01/30 Javascript
使用JS实现图片展示瀑布流效果(简单实例)
2016/09/06 Javascript
JS实现的DIV块来回滚动效果示例
2017/02/07 Javascript
JS实现静态页面搜索并高亮显示功能完整示例
2017/09/19 Javascript
vue中使用refs定位dom出现undefined的解决方法
2017/12/21 Javascript
vue.js+element-ui动态配置菜单的实例
2018/09/07 Javascript
layui的面包屑或者表单不显示的解决方法
2019/09/05 Javascript
vue-cli4.0多环境配置变量与模式详解
2020/12/30 Vue.js
[02:25]DOTA2英雄基础教程 虚空假面
2014/01/02 DOTA
[06:07]辉夜杯现场观众互动 “比谁远送显示器”
2015/12/26 DOTA
[00:14]PWL:老朋友Mushi拍VLOG与中国玩家问好
2020/11/04 DOTA
通过数据库对Django进行删除字段和删除模型的操作
2015/07/21 Python
python使用os.listdir和os.walk获得文件的路径的方法
2017/12/16 Python
Python实现简单查找最长子串功能示例
2019/02/26 Python
python可视化篇之流式数据监控的实现
2019/08/07 Python
python实现简单成绩录入系统
2019/09/19 Python
selenium+Chrome滑动验证码破解二(某某网站)
2019/12/17 Python
Python3使用tesserocr识别字母数字验证码的实现
2021/01/29 Python
Tommy Hilfiger美国官网:美国高端休闲领导品牌
2019/01/14 全球购物
办公室年终个人自我评价
2013/10/28 职场文书
大学军训自我鉴定
2013/12/15 职场文书
销售团队激励口号
2014/06/06 职场文书
岗位安全生产责任书
2014/07/28 职场文书
2015年办公室工作总结范文
2015/03/31 职场文书
幼儿园保育员随笔
2015/08/14 职场文书
jquery插件实现悬浮的菜单
2021/04/24 jQuery