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采集时被封ip的解决方法
Aug 29 PHP
PHP学习笔记之二
Jan 17 PHP
简单的cookie计数器实现源码
Jun 07 PHP
如何取得中文字符串中出现次数最多的子串
Aug 08 PHP
php文件上传的例子及参数详解
Dec 12 PHP
最常用的8款PHP调试工具
Jul 06 PHP
phpcms手机内容页面添加上一篇和下一篇
Jun 05 PHP
PHP滚动日志的代码实现
Jun 10 PHP
php通过排列组合实现1到9数字相加都等于20的方法
Aug 03 PHP
Zend Framework实现多文件上传功能实例
Mar 21 PHP
laravel实现上传图片并在页面显示的例子
Oct 14 PHP
php实现通过stomp协议连接ActiveMQ操作示例
Feb 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 curl模拟post提交数据示例
2013/12/31 PHP
PHP数组排序之sort、asort与ksort用法实例
2014/09/08 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
jquery 图片 上一张 下一张 链接效果(续篇)
2010/04/20 Javascript
jQuery随便控制任意div隐藏的方法
2013/06/28 Javascript
深入解析JavaScript中的变量作用域
2013/12/06 Javascript
javascript计时器事件使用详解
2014/01/07 Javascript
jQuery表格插件datatables用法总结
2014/09/05 Javascript
js实现鼠标经过时图片滚动停止的方法
2015/02/16 Javascript
js实现点击文本框显示日期选择器特效代码分享
2020/05/21 Javascript
json的使用小结
2016/06/08 Javascript
实用jquery操作表单元素的简单代码
2016/07/04 Javascript
Vue 2.x教程之基础API
2017/03/06 Javascript
js仿微信公众平台打标签功能
2017/04/08 Javascript
详解原生js实现offset方法
2017/06/15 Javascript
js匿名函数使用&amp;传参(实例)
2017/09/08 Javascript
讲解vue-router之什么是动态路由
2018/05/28 Javascript
vue.js实现备忘录demo
2019/06/26 Javascript
基于Vue的商品主图放大镜方案详解
2019/09/19 Javascript
使用 Angular RouteReuseStrategy 缓存(路由)组件的实例代码
2019/11/01 Javascript
使用vue-cli4.0快速搭建一个项目的方法步骤
2019/12/04 Javascript
基于JS实现计算24点算法代码实例解析
2020/07/23 Javascript
Python版的文曲星猜数字游戏代码
2013/09/02 Python
python解析文件示例
2014/01/23 Python
python3利用smtplib通过qq邮箱发送邮件方法示例
2017/12/03 Python
代码详解django中数据库设置
2019/01/28 Python
用Python实现BP神经网络(附代码)
2019/07/10 Python
Pytorch中index_select() 函数的实现理解
2019/11/19 Python
2020年10款优秀的Python第三方库,看看有你中意的吗?
2021/01/12 Python
2019年Java面试必问之经典试题
2012/09/12 面试题
基本公共卫生服务健康教育工作方案
2014/05/22 职场文书
人民调解协议书范本
2014/10/11 职场文书
幼儿园2016年感恩节活动总结
2016/04/01 职场文书
解决Jenkins集成SonarQube遇到的报错问题
2021/07/15 Java/Android
日本官方排名前10的动漫,名侦探柯南上榜,第一是一部创造历史的动漫
2022/03/18 日漫
阿里云ECS云服务器快照的概念以及如何使用
2022/04/21 Servers