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 相关文章推荐
论坛头像随机变换代码
Oct 09 PHP
基于PHP异步执行的常用方式详解
Jun 03 PHP
php 去除html标记--strip_tags与htmlspecialchars的区别详解
Jun 26 PHP
PHP连接MySQL查询结果中文显示乱码解决方法
Oct 25 PHP
php从给定url获取文件扩展名的方法
Mar 14 PHP
php字符串分割函数用法实例
Mar 17 PHP
PHP二维数组矩形转置实例
Jul 20 PHP
解决laravel中日志权限莫名变成了root的问题
Oct 17 PHP
PHP常用函数之格式化时间操作示例
Oct 21 PHP
Laravel重定向,a链接跳转,控制器跳转示例
Oct 22 PHP
PHP 图片处理
Sep 16 PHP
Jsonp劫持学习
Apr 01 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教程 预定义变量
2009/10/23 PHP
在PHP中使用FastCGI解析漏洞及修复方案
2015/11/10 PHP
php编程每天必学之验证码
2016/03/03 PHP
弹出模态框modal的实现方法及实例
2017/09/19 PHP
对于Laravel 5.5核心架构的深入理解
2018/02/22 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
JavaScript 定义function的三种方式小结
2009/10/16 Javascript
JavaScript使用过程中需要注意的地方和一些基本语法
2010/08/26 Javascript
js 实现在离开页面时提醒未保存的信息(减少用户重复操作)
2013/01/16 Javascript
用JavaScript获取DOM元素位置和尺寸大小的方法
2013/04/12 Javascript
JS实现点击下载的小例子
2013/07/10 Javascript
JS实现Fisheye效果动感放大菜单代码
2015/10/21 Javascript
js基础知识(公有方法、私有方法、特权方法)
2015/11/06 Javascript
JavaScript高级教程5.6之基本包装类型(详细)
2015/11/23 Javascript
学习javascript面向对象 掌握创建对象的9种方式
2016/01/04 Javascript
基于Bootstrap实现Material Design风格表单插件 附源码下载
2016/04/18 Javascript
浅谈JavaScript中面向对象的的深拷贝和浅拷贝
2016/08/01 Javascript
微信小程序之仿微信漂流瓶实例
2016/12/09 Javascript
vue2.0获取自定义属性的值
2017/03/28 Javascript
详谈js遍历集合(Array,Map,Set)
2017/04/06 Javascript
使用JS实现图片轮播的实例(前后首尾相接)
2017/09/21 Javascript
nodejs+mongodb+vue前后台配置ueditor的示例代码
2018/01/02 NodeJs
CentOS环境中MySQL修改root密码方法
2018/01/07 Javascript
原生js实现Flappy Bird小游戏
2018/12/24 Javascript
Vue CLI 2.x搭建vue(目录最全分析)
2019/02/27 Javascript
浅谈JS的原型和继承
2019/05/08 Javascript
微信小程序缓存过期时间的使用详情
2019/05/12 Javascript
vue axios重复点击取消上一次请求封装的方法
2019/06/19 Javascript
Javascript实现秒表计时游戏
2020/05/27 Javascript
Python字典推导式将cookie字符串转化为字典解析
2019/08/10 Python
Pandas聚合运算和分组运算的实现示例
2019/10/17 Python
详解Python设计模式之策略模式
2020/06/15 Python
TensorFlow的环境配置与安装方法
2021/02/20 Python
Oracle性能调优原则
2012/05/03 面试题
汽车4S店销售经理岗位职责
2015/04/02 职场文书
html+css实现文字折叠特效实例
2021/06/02 HTML / CSS