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(3) php 函数
Feb 15 PHP
php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
Jan 03 PHP
浅析PHP中的字符串编码转换(自动识别原编码)
Jul 02 PHP
淘宝ip地址查询类分享(利用淘宝ip库)
Jan 07 PHP
PHP提示Deprecated: mysql_connect(): The mysql extension is deprecated的解决方法
Aug 28 PHP
PHP session文件独占锁引起阻塞问题解决方法
May 12 PHP
WordPress中自定义后台管理界面配色方案的小技巧
Dec 29 PHP
PHP命令Command模式用法实例分析
Aug 08 PHP
PHP使用SMTP邮件服务器发送邮件示例
Aug 28 PHP
实例讲解php将字符串输出到HTML
Jan 27 PHP
PHP抽象类与接口的区别详解
Mar 21 PHP
基于PHP实现发微博动态代码实例
Dec 11 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最常用的2种设计模式工厂模式和单例模式介绍
2012/08/14 PHP
php 批量查询搜狗sogou代码分享
2015/05/17 PHP
PHP Curl模拟登录微信公众平台、新浪微博实例代码
2016/01/28 PHP
记Laravel调用Gin接口调用formData上传文件的实现方法
2019/12/12 PHP
javascript中call和apply方法浅谈
2013/09/27 Javascript
纯JS实现根据CSS的class选择DOM
2014/03/22 Javascript
jQuery实现购物车多物品数量的加减+总价计算
2014/06/06 Javascript
使用js dom和jquery分别实现简单增删改
2014/09/11 Javascript
AngularJS基础知识
2014/12/21 Javascript
JS留言功能的简单实现案例(推荐)
2016/06/23 Javascript
Angular.js中下拉框实现渲染html的方法
2017/06/18 Javascript
JavaScript阻止表单提交方法(附代码)
2017/08/15 Javascript
es6在react中的应用代码解析
2017/11/08 Javascript
webpack多页面开发实践
2017/12/18 Javascript
JS+WCF实现进度条实时监测数据加载量的方法详解
2017/12/19 Javascript
浅谈JS中几种轻松处理'this'指向方式
2019/09/16 Javascript
Python修改Excel数据的实例代码
2013/11/01 Python
对python指数、幂数拟合curve_fit详解
2018/12/29 Python
Python3.5内置模块之time与datetime模块用法实例分析
2019/04/27 Python
PyQt5重写QComboBox的鼠标点击事件方法
2019/06/25 Python
Kears 使用:通过回调函数保存最佳准确率下的模型操作
2020/06/17 Python
Python自动登录QQ的实现示例
2020/08/28 Python
Python接口自动化测试框架运行原理及流程
2020/11/30 Python
Html5 Canvas 实现一个“刮刮乐”游戏
2019/09/05 HTML / CSS
html5 Canvas画图教程(3)—canvas出现1像素线条模糊不清的原因
2013/01/09 HTML / CSS
西班牙最大的在线滑板和街头服饰商店:Fillow.net
2019/04/15 全球购物
澳大利亚最早和最古老的巨型游戏专家:Yardgames
2020/02/20 全球购物
神话般的珠宝:Ross-Simons
2020/07/13 全球购物
中科前程Java笔试题
2016/11/20 面试题
《少年王勃》教学反思
2014/04/27 职场文书
关于成绩下滑的自我检讨书
2014/09/20 职场文书
医生学习党的群众路线教育实践活动心得体会
2014/11/03 职场文书
介绍信模板
2015/01/31 职场文书
使用 JavaScript 制作页面效果
2021/04/21 Javascript
Python+Tkinter打造签名设计工具
2022/04/01 Python
Ruby使用Mysql2连接操作MySQL
2022/04/19 Ruby