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学习 计数器实例代码
Jun 15 PHP
PHP 文章中的远程图片采集到本地的代码
Jul 30 PHP
php下使用SimpleXML 处理XML 文件
Feb 27 PHP
PHP strtok()函数的优点分析
Mar 02 PHP
PHP5与MySQL数据库操作常用代码 收集
Mar 21 PHP
Smarty中常用变量操作符汇总
Oct 27 PHP
php打造智能化的柱状图程序,用于报表等
Jun 19 PHP
PHP实现连接设备、通讯和发送命令的方法
Oct 13 PHP
WordPress开发中短代码的实现及相关函数使用技巧
Jan 05 PHP
PHP的openssl加密扩展使用小结(推荐)
Jul 18 PHP
php字符串操作常见问题小结
Oct 11 PHP
Laravel 集成 Geetest验证码的方法
May 14 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中DOMElement操作xml文档实例演示
2013/03/26 PHP
2014过年倒计时示例
2014/01/31 PHP
php实现与erlang的二进制通讯实例解析
2014/07/23 PHP
在Win7 中为php扩展配置Xcache
2014/10/08 PHP
PHP5.3新特性小结
2016/02/14 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
2017/09/17 PHP
javascript onkeydown,onkeyup,onkeypress,onclick,ondblclick
2009/02/04 Javascript
jquery事件机制扩展插件 jquery鼠标右键事件。
2011/12/26 Javascript
浅析document.createDocumentFragment()与js效率
2013/07/08 Javascript
javascript:window.open弹出窗口的位置问题
2014/03/18 Javascript
js过滤HTML标签完整实例
2015/11/26 Javascript
基于vue实现分页效果
2017/11/06 Javascript
JavaScript实现构造json数组的方法分析
2018/08/17 Javascript
C#程序员入门学习微信小程序的笔记
2019/03/05 Javascript
React组件对子组件children进行加强的方法
2019/06/23 Javascript
vue中注册自定义的全局js方法
2019/11/15 Javascript
如何使用RoughViz可视化Vue.js中的草绘图表
2021/01/30 Vue.js
[01:01:36]Optic vs paiN 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
Python中获取网页状态码的两个方法
2014/11/03 Python
Python读取ini文件、操作mysql、发送邮件实例
2015/01/01 Python
用实例详解Python中的Django框架中prefetch_related()函数对数据库查询的优化
2015/04/01 Python
python关闭windows进程的方法
2015/04/18 Python
Python实现字典的key和values的交换
2015/08/04 Python
Python使用Selenium+BeautifulSoup爬取淘宝搜索页
2018/02/24 Python
终端命令查看TensorFlow版本号及路径的方法
2018/06/13 Python
python PrettyTable模块的安装与简单应用
2019/01/11 Python
Python opencv相机标定实现原理及步骤详解
2020/04/09 Python
Python3实现打印任意宽度的菱形代码
2020/04/12 Python
Python实现自动整理文件的脚本
2020/12/17 Python
HTML5 Web缓存和运用程序缓存(cookie,session)
2018/01/11 HTML / CSS
Booking.com荷兰:全球酒店网上预订
2017/08/22 全球购物
毕业生面试求职信
2014/06/23 职场文书
教师群众路线剖析材料
2014/09/29 职场文书
关于随地扔垃圾的检讨书
2014/09/30 职场文书
廉政承诺书2015
2015/04/28 职场文书
oracle重置序列从0开始递增1
2022/02/28 Oracle