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 相关文章推荐
模仿OSO的论坛(五)
Oct 09 PHP
PHP 常用数组内部函数(Array Functions)介绍
Jun 05 PHP
浅析关于PHP位运算的简单权限设计
Jun 30 PHP
PHP调用Linux命令权限不足问题解决方法
Feb 07 PHP
php中动态变量用法实例
Jun 10 PHP
php强大的时间转换函数strtotime
Feb 18 PHP
ThinkPHP连接Oracle数据库
Apr 22 PHP
PHP检测链接是否存在的代码实例分享
May 06 PHP
PHP面向对象五大原则之里氏替换原则(LSP)详解
Apr 08 PHP
PHP使用POP3读取邮箱接收邮件的示例代码
Jul 08 PHP
php redis setnx分布式锁简单原理解析
Oct 23 PHP
PHP替换Word中变量并导出PDF图片的实现方法
Nov 26 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 is_file()和is_dir()用于遍历目录时用法注意事项
2010/03/02 PHP
Thinkphp模板中截取字符串函数简介
2014/06/17 PHP
ThinkPHP上使用多说评论插件的方法
2014/10/31 PHP
laravel 解决ajax异步提交数据,并还回填充表格的问题
2019/10/15 PHP
神奇的代码 通杀各种网站-可随意修改复制页面内容
2008/07/17 Javascript
细说浏览器特性检测(2)-通用事件检测
2010/11/05 Javascript
自动刷新网页,自动刷新当前页面,JS调用
2013/06/24 Javascript
jquery的flexigrid无法显示数据提示获取到数据
2013/07/19 Javascript
将HTML的左右尖括号等转义成实体形式的两种实现方式
2014/05/04 Javascript
js实现顶部可折叠的菜单工具栏效果实例
2015/05/09 Javascript
JS中判断字符串中出现次数最多的字符及出现的次数的简单实例
2016/06/03 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
2016/10/14 Javascript
jQuery插件zTree实现的基本树与节点获取操作示例
2017/03/08 Javascript
jQuery实现table中两列CheckBox只能选中一个的示例
2017/09/22 jQuery
vue2.0+vue-router构建一个简单的列表页的示例代码
2019/02/13 Javascript
javascript设计模式 ? 策略模式原理与用法实例分析
2020/04/21 Javascript
vue实现移动端H5数字键盘组件使用详解
2020/08/25 Javascript
原生JS实现拖拽功能
2020/12/16 Javascript
在Python中使用Mako模版库的简单教程
2015/04/08 Python
Python实现对比不同字体中的同一字符的显示效果
2015/04/23 Python
python生成器,可迭代对象,迭代器区别和联系
2018/02/04 Python
PyTorch学习笔记之回归实战
2018/05/28 Python
Python中常用的内置方法
2019/01/28 Python
css3的@media属性实现页面响应式布局示例代码
2014/02/10 HTML / CSS
华为旗下电子商务平台:华为商城
2016/08/06 全球购物
韩国爱茉莉太平洋化妆品美国站:Amore Pacific US
2016/10/28 全球购物
英国和世界各地鲜花速递专家:Arena Flowers
2018/02/10 全球购物
北美女性服装零售连锁店:maurices
2019/06/12 全球购物
Oral-B荷兰:牙医最推荐的品牌
2020/02/25 全球购物
酒店员工检讨书
2014/02/18 职场文书
2014年党的群众路线学习心得体会
2014/11/05 职场文书
先进党支部事迹材料
2014/12/24 职场文书
护士长2015年终工作总结
2015/04/24 职场文书
2015年入党积极分子培养考察意见
2015/08/12 职场文书
MySQL中你可能忽略的COLLATION实例详解
2021/05/12 MySQL
分享python函数常见关键字
2022/04/26 Python