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 相关文章推荐
多数据表共用一个页的新闻发布
Oct 09 PHP
常用的php对象类型判断
Aug 27 PHP
php操作sqlserver关于时间日期读取的小小见解
Nov 29 PHP
深入PHP中慎用双等于(==)的详解
Jun 06 PHP
解析PHP中数组元素升序、降序以及重新排序的函数
Jun 20 PHP
解析thinkphp import 文件内容变量失效的问题
Jun 20 PHP
ThinkPHP提交表单时默认自动转义的解决方法
Nov 25 PHP
php实现的简单美国商品税计算函数
Jul 13 PHP
ThinkPHP中create()方法自动验证表单信息
Apr 28 PHP
php记录搜索引擎爬行记录的实现代码
Mar 02 PHP
windows环境下使用Composer安装ThinkPHP5
May 18 PHP
PHP类的自动加载与命名空间用法实例分析
Jun 05 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
玛琪朵 Macchiato
2021/03/03 咖啡文化
php中使用array_filter()函数过滤空数组的实现代码
2014/08/19 PHP
php中fsockopen用法实例
2015/01/05 PHP
thinkPHP基于ajax实现的菜单与分页示例
2016/07/12 PHP
jquery ajax 同步异步的执行示例代码
2010/06/23 Javascript
基于jQuery的倒计时插件代码
2011/05/07 Javascript
jquery中插件实现自动添加用户的具体代码
2013/11/15 Javascript
JQuery中使用Ajax赋值给全局变量失败异常的解决方法
2014/08/18 Javascript
12306验证码破解思路分享
2015/03/25 Javascript
javascript常用函数(2)
2015/11/05 Javascript
跟我学习javascript的全局变量
2015/11/16 Javascript
JS代码实现百度地图 画圆 删除标注
2016/10/12 Javascript
关于iframe跨域POST提交的方法示例
2017/01/15 Javascript
简单实现jQuery轮播效果
2017/08/18 jQuery
vue element-ui table表格滚动加载方法
2018/03/02 Javascript
vue中datepicker的使用教程实例代码详解
2019/07/08 Javascript
Python实现动态添加类的属性或成员函数的解决方法
2014/07/16 Python
详解Python文本操作相关模块
2017/06/22 Python
Python实现采用进度条实时显示处理进度的方法
2017/12/19 Python
python生成每日报表数据(Excel)并邮件发送的实例
2019/02/03 Python
HTML5+CSS3网页加载进度条的实现,下载进度条的代码实例
2016/12/30 HTML / CSS
html5的新玩法——语音搜索
2013/01/03 HTML / CSS
捷克汽车配件和工具销售网站:TorriaCars
2018/02/26 全球购物
应届毕业生的自我鉴定
2013/11/13 职场文书
新闻记者个人求职的自我评价
2013/11/28 职场文书
银行领导证婚词
2014/01/11 职场文书
小学敬老月活动方案
2014/02/11 职场文书
军训考核自我鉴定
2014/02/13 职场文书
扩大国家免疫规划实施方案
2014/03/21 职场文书
副董事长岗位职责
2014/04/02 职场文书
学期评语大全
2014/04/30 职场文书
分公司任命书
2014/06/06 职场文书
文秘班元旦晚会活动策划方案
2014/08/28 职场文书
给老婆的道歉信
2015/01/20 职场文书
水电工岗位职责
2015/02/14 职场文书
笔记本自带的win11如何跳过联网激活?
2022/04/20 数码科技