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程序之die调试法 快速解决错误
Sep 17 PHP
PHP动态创建Web站点的方法
Aug 14 PHP
PHP 文件系统详解
Sep 13 PHP
php 保留字列表
Oct 04 PHP
PHP跨时区(UTC时间)应用解决方案
Jan 11 PHP
php中get_headers函数的作用及用法的详细介绍
Apr 27 PHP
PHP跳转页面的几种实现方法详解
Jun 08 PHP
CodeIgniter使用phpcms模板引擎
Nov 12 PHP
php获取文件内容最后一行示例
Jan 09 PHP
将二维数组转为一维数组的2种方法
May 26 PHP
PHP MVC框架路由学习笔记
Mar 02 PHP
详解在YII2框架中使用UEditor编辑器发布文章
Nov 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
PHP 的几个配置文件函数
2006/12/21 PHP
php读取excel文件的简单实例
2013/08/26 PHP
php结合js实现点击超链接执行删除确认操作
2014/10/31 PHP
Thinkphp通过一个入口文件如何区分移动端和PC端
2017/04/18 PHP
php实现支持中文的文件下载功能示例
2017/08/30 PHP
基于jQuery实现的Ajax 验证用户名是否存在的实现代码
2011/04/06 Javascript
jquery插件如何使用 jQuery操作Cookie插件使用介绍
2012/12/15 Javascript
Javascript代码在页面加载时的执行顺序介绍
2013/05/03 Javascript
js中switch case循环实例代码
2013/12/30 Javascript
javascritp添加url参数将参数加入到url中
2014/09/25 Javascript
jquery判断当前浏览器的实现代码
2015/11/07 Javascript
js实现图片无缝滚动特效
2020/03/19 Javascript
jQuery中判断对象是否存在的方法汇总
2016/02/24 Javascript
AngularJS Phonecat实例讲解
2016/11/21 Javascript
jquery ui sortable拖拽后保存位置
2017/04/27 jQuery
如何在vue里添加好看的lottie动画
2018/08/02 Javascript
详解js中let与var声明变量的区别
2020/04/05 Javascript
JS实现简单打字测试
2020/06/24 Javascript
Vue 事件的$event参数=事件的值案例
2021/01/29 Vue.js
python批量生成本地ip地址的方法
2015/03/23 Python
Django Highcharts制作图表
2016/08/27 Python
python @property的用法及含义全面解析
2018/02/01 Python
python中的内置函数max()和min()及mas()函数的高级用法
2018/03/29 Python
python实现任意位置文件分割的实例
2018/12/14 Python
选择python进行数据分析的理由和优势
2019/06/25 Python
python 模拟银行转账功能过程详解
2019/08/06 Python
您附近的水疗和健康场所:Spafinder(美国)
2019/07/05 全球购物
Chupi官网:在爱尔兰手工制作的订婚、结婚戒指和精美珠宝
2020/09/28 全球购物
SQL中where和having的区别
2012/06/17 面试题
行政助理求职自荐信
2013/10/26 职场文书
读书活动总结范文
2014/04/26 职场文书
村创先争优活动总结
2014/08/28 职场文书
2014年光棍节活动策划方案(创意集锦)
2014/09/29 职场文书
费用申请报告范文
2015/05/15 职场文书
2015年妇委会工作总结
2015/05/22 职场文书
《棉鞋里的阳光》教学反思
2016/02/20 职场文书