php并发编程-转自:http://www.cnblogs.com/jingzhishen/p/4328740.htmlphp
并发下常见的加锁及锁的PHP具体实现html
http://www.cnblogs.com/scotoma/archive/2010/09/26/1836312.htmlmysql
在最近的项目中有这样的场景web
1.生成文件的时候,因为多用户都有权限进行生成,防止并发下,致使生成的结果出现错误,须要对生成的过程进行加锁,只允许一个用户在一个时间内进行操做,这个时候就须要用到锁了,将这个操做过程锁起来.sql
2.在用了cache的时候,cache失效可能致使瞬间的多数并发请求穿透到数据库此时也能够得须要用锁在同一并发的过程当中将这个操做锁定.数据库
针对以上的2种状况,如今的解决方法是对处理过程进行锁机制,经过PHP实现以下编程
用到了Eaccelerator的内存锁 和 文件锁,原理以下浏览器
判断系统中是否安了EAccelerator 若是有则使用内存锁,若是不存在,则进行文件锁缓存
根据带入的key的不一样能够实现多个锁直接的并行处理,相似Innodb的行级锁安全
使用以下:
$lock = new CacheLock('key_name');
$lock->lock();
//logic here
$lock->unlock();
//使用过程当中须要注意下文件锁所在路径须要有写权限.
具体类以下:
<?php /** * CacheLock 进程锁,主要用来进行cache失效时的单进程cache获取,防止过多的SQL请求穿透到数据库 * 用于解决PHP在并发时候的锁控制,经过文件/eaccelerator进行进程间锁定 * 若是没有使用eaccelerator则进行进行文件锁处理,会作对应目录下产生对应粒度的锁 * 使用了eaccelerator则在内存中处理,性能相对较高 * 不一样的锁之间并行执行,相似mysql innodb的行级锁 * 本类在sunli的phplock的基础上作了少量修改 http://code.google.com/p/phplock * @author yangxinqi * */ class CacheLock { //文件锁存放路径 private $path = null; //文件句柄 private $fp = null; //锁粒度,设置越大粒度越小 private $hashNum = 100; //cache key private $name; //是否存在eaccelerator标志 private $eAccelerator = false; /** * 构造函数 * 传入锁的存放路径,及cache key的名称,这样能够进行并发 * @param string $path 锁的存放目录,以"/"结尾 * @param string $name cache key */ public function __construct($name,$path='lock\\') { //判断是否存在eAccelerator,这里启用了eAccelerator以后能够进行内存锁提升效率 $this->eAccelerator = function_exists("eaccelerator_lock"); if(!$this->eAccelerator) { $this->path = $path.($this->_mycrc32($name) % $this->hashNum).'.txt'; } $this->name = $name; } /** * crc32 * crc32封装 * @param int $string * @return int */ private function _mycrc32($string) { $crc = abs (crc32($string)); if ($crc & 0x80000000) { $crc ^= 0xffffffff; $crc += 1; } return $crc; } /** * 加锁 * Enter description here ... */ public function lock() { //若是没法开启ea内存锁,则开启文件锁 if(!$this->eAccelerator) { //配置目录权限可写 $this->fp = fopen($this->path, 'w+'); if($this->fp === false) { return false; } return flock($this->fp, LOCK_EX); }else{ return eaccelerator_lock($this->name); } } /** * 解锁 * Enter description here ... */ public function unlock() { if(!$this->eAccelerator) { if($this->fp !== false) { flock($this->fp, LOCK_UN); clearstatcache(); } //进行关闭 fclose($this->fp); }else{ return eaccelerator_unlock($this->name); } } }
本类在孙立同窗的类的基础上作了小点改进的了.具体能够看 http://code.google.com/p/phplock 感谢孙同窗的分享精神!
Apache + PHP 的并发访问
文章地址:http://www.cnblogs.com/WestContinent/archive/2013/03/25/2981667.html
1.书写例程:
作成一个测试用的PHP文件代码以下:
<?php //为了测试是否多个用户访问的时候这个值是公用的,即:是否临界资源 $count = 0; //循环十次,消耗十秒,模拟一个费时操做 for ($i=1; $i<=10; $i++,$count++) { echo getTime()." i is $i and count is $count.</br>"; sleep(1); } /** * 得到当前时间,返回字符串,包含毫秒数 * 格式:yyyy-MM-dd HH:mm:ss.fff */ function getTime() { $currentTime = Date('Y-m-d H:i:s');//Get currentTime str $milisecond = microtime(); $splitmiliTime = explode('.', $milisecond); $milisecond = $splitmiliTime[1]; $milisecond = substr($milisecond, 0,3); $currentTime = $currentTime.'.'.$milisecond; return $currentTime; } ?>
2.把上面作成的文件Copy到Apache的发布目录(通常是Htdocs,可是能够配置)
3.打开两个浏览器同时访问发布PHP页面
分别获得以下结果
浏览器1
2013-03-25 14:55:42.128 i is 1
and
count
is 0.
2013-03-25 14:55:43.138 i is 2
and
count
is 1.
2013-03-25 14:55:44.152 i is 3
and
count
is 2.
2013-03-25 14:55:45.169 i is 4
and
count
is 3.
2013-03-25 14:55:46.180 i is 5
and
count
is 4.
2013-03-25 14:55:47.194 i is 6
and
count
is 5.
2013-03-25 14:55:48.208 i is 7
and
count
is 6.
2013-03-25 14:55:49.222 i is 8
and
count
is 7.
2013-03-25 14:55:50.236 i is 9
and
count
is 8.
2013-03-25 14:55:51.250 i is 10
and
count
is 9.
|
浏览器2
2013-03-25 14:55:41.286 i is 1
and
count
is 0.
2013-03-25 14:55:42.296 i is 2
and
count
is 1.
2013-03-25 14:55:43.310 i is 3
and
count
is 2.
2013-03-25 14:55:44.324 i is 4
and
count
is 3.
2013-03-25 14:55:45.339 i is 5
and
count
is 4.
2013-03-25 14:55:46.355 i is 6
and
count
is 5.
2013-03-25 14:55:47.367 i is 7
and
count
is 6.
2013-03-25 14:55:48.402 i is 8
and
count
is 7.
2013-03-25 14:55:49.645 i is 9
and
count
is 8.
2013-03-25 14:55:50.658 i is 10
and
count
is 9.
|
4.结论
从上面的试验结果能够获得以下结论,由于两组测试数据中的时间犬牙交错,两个用户在耗时操做中并无出现某一个用户长时间占用执行时间片的状况。说明Apache+Php(loadmodule)是支持多用户并行操做的。另外全局变量Count在两个用户同时访问的时候都是以全新的状态出现的,所以Apache+Php(loadmodule)不支持内存缓存数据,也就是说在多用户并发访问的状况下每次访问都会开辟新的内存。那么若是须要对多用户的操做作同步,只能使用文件锁的方式来实现了。
加锁解锁PHP实现
文章地址:http://blog.csdn.net/topasstem8/article/details/6735240
PHP并无完善的线程支持,甚至部署到基于线程模型的httpd服务器都会产生一些问题,但即便是多进程模型下的PHP,也不免出现多进程共同访问同一 资源的状况。好比整个程序共享的数据缓存,或者由于资源受限而必须对特定处理过程进行排队,以及针对每一个用户生成惟一的某种标识的情形。PHP语言自身没 有提供进程互斥和锁定机制,于是使得在这些状况下的编程遇到了困难,目前了解到的可选的办法有如下这些:
一、利用MySQL的锁定机制来实现互斥。缺点是增大了数据库服务器的链接负担,而且使得程序依赖于数据库服务才能正常工做。
二、利用文件锁机制。也就是利用flock函数经过文件实现锁定和互斥机制,来模拟通用编程模型下的锁定原语的工做方式。这种方式在之前以纯文本文件为存储引擎的时代成为保护数据完整性的必备元素,如今在使用文本文件做为缓存媒介的场合也至关常见。PmWiki应该也是使用了这个机制来对多人同时编辑一个页面的情形进行提醒。不过文件锁机制多少会调用到宿主操做系统上的文件锁特性,所以在使用时必定要检查服务器操做系统是否为PHP环境提供了完善可靠的文件锁机制。
三、利用共享内存空间计数。PHP能够利用shmop_open函数开辟一块内存空间,在服务进程之间共享数据,为了保证共享数据的互斥安全访问,可使用 sem_get、sem_acquire和sem_release这组函数实现共享计数锁定机制。这种办法在后台实际是调用了系统的ipc 服务来实现。
用 PHP 编写支持高并发的网站,须要作什么处理?
文章地址:http://www.zhihu.com/question/20049768
一、Webserver (Nginx) :这一层是能够轻松分布式部署的,结合智能DNS解析能够简易地防止单点故障、实现区域访问加速,结合LVS很容易实现负载均衡。这一层主要是负责处理静态请求和转发PHP请求至第二层的PHP处理节点,至于静态资源地址(http://misc.xxxx.com)能够单独拿出来部署,或者直接使用商用的云存储服务(国内七牛不错,国外有Amazon S3)
二、PHP 处理节点:一个节点其实就是一个监听特定端口的系统进程,webserver的请求经过负载均衡器(我用的AWS的loadbalancer)进行分发, 很好实现分布式和负载均衡。我如今用的仍是php自带的php-fpm,其实facebook出的hhvm性能很是强悍,可是还不能100%经过我项目的 单元测试,等hhvm成熟事后能够平滑替换
三、高速缓存:用的memcached,这一层的做用主要是减轻数据库IO和加快热数据 访问,缓存策略与程序耦合度较高,不赘述,但简单地说有两种方式,一种是在程序的全局层面加一个缓存处理,这种方法代码耦合度低,可是有效命中率不高,有 些项目不必定适应,另外一种是在具体的数据存取处加缓存处理,这种办法程序耦合度较高,可是缓存命中率很是高,几乎没有无效缓存存在,我用的是这种。
四、数据库 :我如今的项目数据规模不大,暂时只用了单台数据库,可是程序逻辑上已作好了数据库线性扩展的准备。其实数据库层的扩展是老生常谈了,经常使用手段是分库分 表,这一块须要在前期的代码就打下基础,另外更平滑地手段是使用中间件,好比360的Atlas,阿里巴巴的cobar,淘宝的TDDL,中间件能够在不 大范围变动代码的状况下扩展,可是具体的使用场景仍是有限的,具体项目还需单独考察。
五、其 他:根据不一样的项目,架构还能够选择性地使用队列,我如今用的beantalkd,Redis也是一个很好的选择。队列经常使用的使用环境是邮件发送和站内消息推送上面,可是在某些场景下也能够做为核心数据库的缓冲,对应对大并发或者突发性流量也是不错的选择