- 浏览: 339479 次
文章分类
最新评论
-
亚当爱上java:
"给pre-commit添加可执行权限:chmod ...
svn强制要求提交注释--pre-commit钩子 -
rosasyou:
不知道这篇文章是怎么才让人看的?估计不是浏览器兼容问题。 ,与 ...
Zend Framework的DB处理 -
jinjiankang:
$youngest=`svnlook youngest $sv ...
svn备份策略 -
wangxc:
你好,我按照你介绍的方法在创建完weekly_backup.p ...
svn备份策略 -
yangfuchao418:
...
关于memcached的浅见
对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!!用一般的文件操作方法完全没有问题。但如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失。
例如:一个在线聊天室(这里假定把聊天内容写入文件),在同一时刻,用户A和用户B都要操作数据保存文件,首先是A打开了文件,然后更新里面的数据,但这里B也正好也打开了同一个文件,也准备更新里面的数据。当A把写好的文件保存时,这里其实B已经打开了文件。但当B再把文件保存回去时,这里已经造成了数据的丢失,因为这里B用户完全不知道它所打开的文件在它对其进行更改时,A用户也更改了这个文件,所以最后B用户保存更改时,用户A的更新就被会丢失。
对于这样的问题,一般的解决方案时当一进程对文件进行操作时,首先对其它进行加锁,意味着这里只有该进程有权对文件进行读取,其它进程如果现在读,是完全没有问题,但如果这时有进程试图想对其进行更新,会遭到操作拒绝,先前对文件进行加锁的进程这时如果对文件的更新操作完毕,这就释放独占的标识,这时文件又恢复到了可更改的状态。接下来同理,如果那个进程在操作文件时,文件没有加锁,这时,它就可以放心大胆的对文件进行锁定,独自享用。
所以一般的方案会是:
$fp = fopen ( "/tmp/lock.txt", "w+" );
if (flock ( $fp, LOCK_EX )) {
fwrite ( $fp, "Write something here\n" );
flock ( $fp, LOCK_UN );
} else {
echo "Couldn't lock the file !";
}
fclose ( $fp );
但在PHP中,flock似乎工作的不是那么好!在多并发情况下,似乎是经常独占资源,不即时释放,或者是根本不释放,造成死锁,从而使服务器的cpu占用很高,甚至有时候会让服务器彻底死掉。好像在很多linux/unix系统中,都会有这样的情况发生。
所以使用flock之前,一定要慎重考虑。
那么就没有解决方案了吗?其实也不是这样的。如果flock()我们使用得当,完全可能解决死锁的问题。当然如果不考虑使用flock()函数,也同样会有很好的解决方案来解决我们的问题。
经过我个人的搜集和总结,大致归纳了解决方案有如下几种。
方案一:对文件进行加锁时,设置一个超时时间.
大致实现如下:
if ($fp = fopen ( $fileName, 'a' )) {
$startTime = microtime ();
do {
$canWrite = flock ( $fp, LOCK_EX );
if (! $canWrite)
usleep ( round ( rand ( 0, 100 ) * 1000 ) );
} while ( (! $canWrite) && ((microtime () - $startTime) < 1000) );
if ($canWrite) {
fwrite ( $fp, $dataToSave );
}
fclose ( $fp );
}
超时设置为1ms,如果这里时间内没有获得锁,就反复获得,直接获得到对文件操作权为止,当然。如果超时限制已到,就必需马上退出,让出锁让其它进程来进行操作。
方案二:不使用flock函数,借用临时文件来解决读写冲突的问题。
大致原理如下:
1。将需要更新的文件考虑一份到我们的临时文件目录,将文件最后修改时间保存到一个变量,并为这个临时文件取一个随机的,不容易重复的文件名。
2。当对这个临时文件进行更新后,再检测原文件的最后更新时间和先前所保存的时间是否一致。
3。如果最后一次修改时间一致,就将所修改的临时文件重命名到原文件,为了确保文件状态同步更新,所以需要清除一下文件状态。
4。但是,如果最后一次修改时间和先前所保存的一致,这说明在这期间,原文件已经被修改过,这时,需要把临时文件删除,然后返回false,说明文件这时有其它进程在进行操作。
大致实现代码如下:
<?php
$dir_fileopen = "tmp";
function randomid() {
return time () . substr ( md5 ( microtime () ), 0, rand ( 5, 12 ) );
}
function cfopen($filename, $mode) {
global $dir_fileopen;
clearstatcache ();
do {
$id = md5 ( randomid ( rand (), TRUE ) );
$tempfilename = $dir_fileopen . "/" . $id . md5 ( $filename );
} while ( file_exists ( $tempfilename ) );
if (file_exists ( $filename )) {
$newfile = false;
copy ( $filename, $tempfilename );
} else {
$newfile = true;
}
$fp = fopen ( $tempfilename, $mode );
return $fp ? array ($fp, $filename, $id, @filemtime ( $filename ) ) : false;
}
function cfwrite($fp, $string) {
return fwrite ( $fp [0], $string );
}
function cfclose($fp, $debug = "off") {
global $dir_fileopen;
$success = fclose ( $fp [0] );
clearstatcache ();
$tempfilename = $dir_fileopen . "/" . $fp [2] . md5 ( $fp [1] );
if ((@filemtime ( $fp [1] ) == $fp [3]) || ($fp [4] == true && ! file_exists ( $fp [1] )) || $fp [5] == true) {
rename ( $tempfilename, $fp [1] );
} else {
unlink ( $tempfilename );
//说明有其它进程 在操作目标文件,当前进程被拒绝
$success = false;
}
return $success;
}
$fp = cfopen ( 'lock.txt', 'a+' );
cfwrite ( $fp, "welcome to beijing.\n" );
fclose ( $fp, 'on' );
对于上面的代码所使用的函数,需要说明一下:
1.rename();重命名一个文件或一个目录,该函数其实更像linux里的mv。更新文件或者目录的路径或名字很方便。
但当我在window测试上面代码时,如果新文件名已经存在,会给出一个notice,说当前文件已经存在。但在linux下工作的很好。
2.clearstatcache();清除文件的状态.php将缓存所有文件属性信息,以提供更高的性能,但有时,多进程在对文件进行删除或者更新操作时,php没来得及更新缓存里的文件属性,容易导致访问到最后更新时间不是真实的数据。所以这里需要使用该函数对已保存的缓存进行清除。
方案三:对操作的文件进行随机读写,以降低并发的可能性。
在对用户访问日志进行记录时,这种方案似乎被采用的比较多。
先前需要定义一个随机空间,空间越大,并发的的可能性就越小,这里假设随机读写空间为[1-500],那么我们的日志文件的分布就为log1~到log500不等。每一次用户访问,都将数据随机写到log1~log500之间的任一文件。
在同一时刻,有2个进程进行记录日志,A进程可能是更新的log32文件,而B进程呢?则此时更新的可能就为log399.要知道,如果要让B进程也操作log32,概率基本上为1/500,差不多约等于零。
在需要对访问日志进行分析时,这里我们只需要先将这些日志合并,再进行分析即可。
使用这种方案来记录日志的一个好处时,进程操作排队的可能性比较小,可以使进程很迅速的完成每一次操作。
方案四:将所有要操作的进程放入一个队列中。然后专门放一个服务完成文件操作。
队列中的每一个排除的进程相当于第一个具体的操作,所以第一次我们的服务只需要从队列中取得相当于具体操作事项就可以了,如果这里还有大量的文件操作进程,没关系,排到我们的队列后面即可,只要愿意排,队列的多长都没关系。
对于以前几种方案,各有各的好处!大致可能归纳为两类:
1。需要排队(影响慢)比如方案一、二、四
2。不需要排队。(影响快)方案三
在设计缓存系统时,一般我们不会采用方案三。因为方案三的分析程序和写入程序是不同步的,在写的时间,完全不考虑到时候分析的难度,只管写的行了。试想一下,如我们在更新一个缓存时,如果也采用随机文件读写法,那么在读缓存时似乎会增加很多流程。但采取方案一、二就完全不一样,虽然写的时间需要等待(当获取锁不成功时,会反复获取),但读文件是很方便的。添加缓存的目的就是要减少数据读取瓶颈,从而提高系统性能。
从上为个人经验和一些资料的总结,有什么不对的地方,或者没有谈到的地方,欢迎各位同学指正。
发表评论
-
图片压缩的一些心得
2010-11-03 11:45 1955http://blog.lizhigang.net/arc ... -
PHP程序员面临的成长瓶颈
2010-10-25 10:06 1978作为Web开发中应用最广泛的语言之一,PHP有着大量的粉丝 ... -
URL重写相关
2010-07-26 18:13 1153初级URL重写指南 http://lamp.lin ... -
关于PHP的mod_rewrite重写模块技术个人觉得最好的一篇文章
2010-07-26 09:30 2188最近手里一个PHP项目要用到mod_rewrite模块,很 ... -
PHP源代码分析- tick(s)
2010-07-24 10:13 1941By Altair, http://www.phpint ... -
php多线程编程
2010-07-21 23:52 985http://www.cnblogs.com/niniwzw/ ... -
php pcntl_fork和pcntl_fork 的用法
2010-07-21 22:23 2102http://www.jb51.net/article/177 ... -
探讨高并发写入文件内容
2010-07-11 22:48 2790读写相关的问题是永远存在的,文件锁就是为了解决这个问题而做的, ... -
HTTP POST from PHP, without cURL
2010-07-06 17:28 1583Update May 2010: This is one ... -
php fsockopen解决办法。
2010-07-06 15:07 3144Author:David | English Ver ... -
用 PHP V5 开发多任务应用程序
2010-07-04 00:39 1185http://www.ibm.com/developerw ... -
git使用总结
2010-07-02 23:51 1284http://zhwen.org/?p=articles/gi ... -
Linux消息队列原理与应用
2010-07-02 18:03 9450http://www.wanglong-neu.cn/ ... -
我说PHPer的水平区分(转载)
2010-07-02 10:55 1424说句实话,写这个真够无 ... -
正则表达式解题经验谈
2010-06-29 22:08 1056正则表达式解题经验谈 ... -
深入浅出之正则表达式
2010-06-28 21:14 766dragon.cnblogs.com/archive/2006 ... -
stream_set_blocking让程序无阻塞
2010-06-28 09:48 1350stream_set_blocking让程序 ... -
什么是Socket?Socket协议的形象描述
2010-06-28 00:11 1551socket的英文原义是“ ... -
完善匹配中文的Php正则表达式
2010-06-11 16:15 2258这段时间试图使用php正 ... -
php反射
2010-06-07 20:14 14841。用途: 该扩展分析php程序,导出或提取出关于类、方法、属 ...
相关推荐
excel文件读写excel文件读写excel文件读写
php读写json文件php读写json文件php读写json文件php读写json文件
文件读写监控工具文件读写监控工具文件读写监控工具文件读写监控工具文件读写监控工具文件读写监控工具文件读写监控工具
文件读写 文件读写文件读写 文件读写文件读写 文件读写
读写文件 状态栏操作
用C语言实现的简单的文件读写,,适合C初学者,,,熟悉文件读写操作,
java文件读写操作大全java文件读写操作大全java文件读写操作大全java文件读写操作大全java文件读写操作大全
C++文件读写操作C++文件读写操作 C++文件读写操作C++文件读写操作
Android - 文件读写操作 方法总结
最近在用java的IO包下面的RandomAccessFile类读写中文文件时遇到了乱码问题,解决不了。于是索性自己写个类,可以进行中文文件读写而不乱码。 压缩包里提供了.jar包和源代码。 ************************************...
本文档主要系统性的总结和阐述了与Java并发相关的知识点
1、 文件读写 包括两个内容:查找文件中“java”字符串的个数;利用命令行参数显示文件的最后指定行。 在查找“java”字符串个数的程序中,先读出文件内容,再逐个字符对比,找出“java”字符,最终把结果写入另一...
在android开发中,我们经常用到文件的读写权限
易语言大文件读写模块源码,大文件读写模块,初始化,取总行数,取行文本,条件查询
MFC INI文件读写;MFC INI文件读写;MFC INI文件读写;MFC INI文件读写;MFC INI文件读写;
qt 内存 映射 大文件读写
C#文件的读写 介绍了c#基础中文件读写课程中一些常用类级方法
本文主要给大家简单讲解如何用 asyncio.Future 对象来封装文件的异步读写。有需要的小伙伴可以参考下
对于C#中文件的读写操作,写入文件内容,读取文件内容,并且选择对应文件进行删除操作。
linux C文件读写 初学练手代码 内容很简单,就实现简单的文件读写功能