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的计数器程序
Oct 09 PHP
PHP 编写的 25个游戏脚本
May 11 PHP
php5.3 不支持 session_register() 此函数已启用的解决方法
Nov 12 PHP
php和jquery实现地图区域数据统计展示数据示例
Feb 12 PHP
php命令行使用方法和命令行参数说明
Apr 08 PHP
php中将一段数据存到一个txt文件中并显示其内容
Aug 15 PHP
php实现删除指定目录下相关文件的方法
Oct 20 PHP
PHP验证码类ValidateCode解析
Jan 07 PHP
form表单传递数组数据、php脚本接收的实例
Feb 09 PHP
php简单处理XML数据的方法示例
May 19 PHP
php实现表单提交上传文件功能
May 28 PHP
解决laravel5中auth用户登录其他页面获取不到登录信息的问题
Oct 08 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
用Flash图形化数据(一)
2006/10/09 PHP
基于在生产环境中使用php性能测试工具xhprof的详解
2013/06/03 PHP
Yii安装与使用Excel扩展的方法
2016/07/13 PHP
PHP实现的观察者模式实例
2017/06/21 PHP
如何通过Apache在本地配置多个虚拟主机
2020/07/29 PHP
JavaScript按位运算符的应用简析
2014/02/04 Javascript
使用jquery组件qrcode生成二维码及应用指南
2015/02/22 Javascript
Javascript的表单与验证-非空验证
2016/03/18 Javascript
去除html代码里面的script正则方法
2016/05/19 Javascript
JS实现六边形3D拖拽翻转效果的方法
2016/09/11 Javascript
AngularJs 常用的过滤器
2017/05/15 Javascript
了解VUE的render函数的使用
2017/06/08 Javascript
JavaScript上传文件时不用刷新页面方法总结(推荐)
2017/08/15 Javascript
实例解析Vue.js下载方式及基本概念
2018/05/11 Javascript
详解vue2.6插槽更新v-slot用法总结
2019/03/09 Javascript
jquery实现垂直无限轮播的方法分析
2019/07/16 jQuery
原生js实现可兼容PC和移动端的拖动滑块功能详解【测试可用】
2019/08/15 Javascript
layui form表单提交后实现自动刷新
2019/10/25 Javascript
[47:03]完美世界DOTA2联赛PWL S3 access vs LBZS 第一场 12.20
2020/12/23 DOTA
Python多线程结合队列下载百度音乐的方法
2015/07/27 Python
Python实现字符串匹配的KMP算法
2019/04/04 Python
使用python3批量下载rbsp数据的示例代码
2019/12/20 Python
Pythonic版二分查找实现过程原理解析
2020/08/11 Python
python 检测图片是否有马赛克
2020/12/01 Python
天猫精选:上天猫,就够了
2016/09/21 全球购物
Spartoo荷兰:鞋子、包包和服装
2018/07/12 全球购物
国旗下演讲稿
2014/05/08 职场文书
汽车运用工程专业求职信
2014/06/18 职场文书
超市促销活动总结
2014/07/01 职场文书
党员对照检查材料整改措施思想汇报
2014/09/26 职场文书
校车安全管理责任书
2015/05/11 职场文书
唐山大地震的观后感
2015/06/05 职场文书
《圆的周长》教学反思
2016/02/17 职场文书
left join、inner join、right join的区别
2021/04/05 MySQL
关于vue中如何监听数组变化
2021/04/28 Vue.js
Vue Element-ui表单校验规则实现
2021/07/09 Vue.js