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+mysql写的留言本
Oct 09 PHP
php判断字符以及字符串的包含方法属性
Aug 30 PHP
php获取地址栏信息的代码
Oct 08 PHP
国外比较好的几个的Php开源建站平台小结
Apr 22 PHP
PHP如何实现Unicode和Utf-8编码相互转换
Jul 29 PHP
PHP实现的多文件上传类及用法示例
May 06 PHP
24条货真价实的PHP代码优化技巧
Jul 28 PHP
PHP简单创建压缩图的方法
Aug 24 PHP
Symfony2创建基于域名的路由相关示例
Nov 14 PHP
php使用imagecopymerge()函数创建半透明水印
Jan 25 PHP
CI框架教程之优化验证码机制详解【验证码辅助函数】
Apr 16 PHP
php实现根据身份证获取精准年龄
Feb 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
自制汽车收音机天线:收听广播的技巧和方法
2021/03/02 无线电
PHP中使用crypt()实现用户身份验证的代码
2012/09/05 PHP
zf框架的校验器使用使用示例(自定义校验器和校验器链)
2014/03/13 PHP
PHP操作MySQL事务实例
2014/11/05 PHP
Yii开启片段缓存的方法
2016/03/28 PHP
php反射学习之不用new方法实例化类操作示例
2019/06/14 PHP
JS 实现导航栏悬停效果(续2)
2013/09/24 Javascript
node.js中的fs.chmod方法使用说明
2014/12/18 Javascript
JavaScript中的数据类型转换方法小结
2015/10/26 Javascript
Bootstrap项目实战之首页内容介绍(全)
2016/04/25 Javascript
JS数组操作(数组增加、删除、翻转、转字符串、取索引、截取(切片)slice、剪接splice、数组合并)
2016/05/20 Javascript
微信小程序组件 contact-button(客服会话按钮)详解及实例代码
2017/01/10 Javascript
微信小程序实现流程进度的图样式功能
2018/01/16 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
JS严格模式知识点总结
2018/02/27 Javascript
通过jquery toggleClass()属性制作文章段落更改背景颜色
2018/05/21 jQuery
vue实现文件上传功能
2018/08/13 Javascript
Vue开发之watch监听数组、对象、变量操作分析
2019/04/25 Javascript
vuex存储token示例
2019/11/11 Javascript
JavaScript 自定义html元素鼠标右键菜单功能
2019/12/02 Javascript
Vue Object 的变化侦测实现代码
2020/04/15 Javascript
[00:17]游戏风云独家报道:DD赛后说出数字秘密 吓死你们啊!
2014/07/13 DOTA
Python 字符串中的字符倒转
2008/09/06 Python
Python使用pymysql小技巧
2017/06/04 Python
Python使用OpenCV进行标定
2018/05/08 Python
Python基础教程之异常详解
2019/01/10 Python
关于Python3 类方法、静态方法新解
2019/08/30 Python
Django 5种类型Session使用方法解析
2020/04/29 Python
学python需要去培训机构吗
2020/07/01 Python
DJI大疆无人机官方商城:全球领先的无人飞行器研发和生产商
2016/12/21 全球购物
英国著名药妆店:Superdrug
2021/02/13 全球购物
linux比较文件内容的命令是什么
2013/03/04 面试题
介绍一下Ruby的多线程处理
2013/02/01 面试题
2014院党委领导班子对照检查材料思想汇报
2014/09/24 职场文书
护士求职自荐信
2015/03/25 职场文书
家长必看:义务教育,不得以面试 评测等名义选拔学生
2019/07/09 职场文书