PHP并发 加悲观锁(1)

简介:

php如何解决多线程读写同一文件

大家都知道,PHP是没有多线程概念的,尽管如此我们仍然可以用“不完美”的方法来模拟多线程。简单的说,就是队列处理。通过对文件进行加锁和解锁,来实现。当一个文件被一个用户操作时,该文件是被锁定的,其他用户只能等待,确实不够完美,但是也可以满足一些要求不高的应用。

上限判断,关键数据的写入扣钱之类

用到了Eaccelerator的内存锁和文件锁,原理:判断系统中是否安了EAccelerator如果有则使用内存锁,如果不存在,则进行文件锁。根据带入的key的不同可以实现多个锁直接的并行处理 ,类似Innodb的行级锁。

具体类如下:file_put_contents($file, $string, LOCK_EX );

Java代码   收藏代码
  1. <?php  
  2.   
  3. /** 
  4.  * CacheLock 进程锁,主要用来进行cache失效时的单进程cache获取,防止过多的SQL请求穿透到数据库 
  5.  * 用于解决PHP在并发时候的锁控制,通过文件/eaccelerator进行进程间锁定 
  6.  * 如果没有使用eaccelerator则进行进行文件锁处理,会做对应目录下产生对应粒度的锁 
  7.  * 使用了eaccelerator则在内存中处理,性能相对较高 
  8.  * 不同的锁之间并行执行,类似mysql innodb的行级锁 
  9.  * 
  10.  */  
  11. class CacheLock  
  12. {  
  13.     //文件锁存放路径  
  14.     private $path = null;  
  15.     //文件句柄  
  16.     private $fp = null;  
  17.     //锁粒度,设置越大粒度越小  
  18.     private $hashNum = 100;  
  19.     //cache key  
  20.     private $name;  
  21.     //是否存在eaccelerator标志  
  22.     private $eAccelerator = false;  
  23.   
  24.     /** 
  25.      * 构造函数 
  26.      * 传入锁的存放路径,及cache key的名称,这样可以进行并发 
  27.      * @param string $path 锁的存放目录 
  28.      * @param string $name cache key 
  29.      */  
  30.     public function __construct($name, $path = 'lock')  
  31.     {  
  32.         //判断是否存在eAccelerator,这里启用了eAccelerator之后可以进行内存锁提高效率  
  33.         $this->eAccelerator = function_exists("eaccelerator_lock");  
  34.         if (!$this->eAccelerator) {  
  35.             if (!is_dir($path)) { //目录设置写权限  
  36.                 mkdir($path, 0777);  
  37.                 chmod($path, 0777);  
  38.             }  
  39.             $this->path = realpath($path) . DIRECTORY_SEPARATOR . ($this->_mycrc32($name) % $this->hashNum) . '.txt';  
  40.         }  
  41.         $this->name = $name;  
  42.     }  
  43.   
  44.     /** 
  45.      * crc32 
  46.      * crc32封装 相同的string会算出唯一值 
  47.      * @param string $string 
  48.      * @return int 
  49.      */  
  50.     private function _mycrc32($string)  
  51.     {  
  52.         $crc = abs(crc32($string));  
  53.         if ($crc & 0x80000000) {  
  54.             $crc ^= 0xffffffff;  
  55.             $crc += 1;  
  56.         }  
  57.         return $crc;  
  58.     }  
  59.   
  60.     /** 
  61.      * 加锁 
  62.      * Enter description here ... 
  63.      */  
  64.     public function lock()  
  65.     {  
  66.         //如果无法开启ea内存锁,则开启文件锁  
  67.         if (!$this->eAccelerator) {  
  68.             //配置目录权限可写  
  69.             $this->fp = fopen($this->path, 'w+');  
  70.             if ($this->fp === false) {  
  71.                 return false;  
  72.             }  
  73.             return flock($this->fp, LOCK_EX);  
  74.         } else {  
  75.             return eaccelerator_lock($this->name);  
  76.         }  
  77.     }  
  78.   
  79.     /** 
  80.      * 解锁 
  81.      * Enter description here ... 
  82.      */  
  83.     public function unlock()  
  84.     {  
  85.         if (!$this->eAccelerator) {  
  86.             if ($this->fp !== false) {  
  87.                 flock($this->fp, LOCK_UN);  
  88.                 $this->deleteCache();  
  89.             }  
  90.             //进行关闭  
  91.             fclose($this->fp);  
  92.         } else {  
  93.             return eaccelerator_unlock($this->name);  
  94.         }  
  95.     }  
  96.     //删除零时文件  
  97.     private function deleteCache()  
  98.     {  
  99.         clearstatcache(); //清除文件状态缓存  
  100.   
  101.         //删除1小时前的文件  
  102.         $cacheDir = dirname($this->path);  
  103.         $files = scandir($cacheDir);  
  104.         foreach ($files as $file) {  
  105.             if (strlen($file) > 2 && time() > (filemtime($cacheDir . DIRECTORY_SEPARATOR . $file) + 3600)) {  
  106.                 @unlink($cacheDir . DIRECTORY_SEPARATOR . $file);  
  107.             }  
  108.         }  
  109.     }  
  110. }  
  111. ?>  

 使用如下:

Java代码   收藏代码
  1. $lock = new CacheLock($orderNo); //要排队访问文件要相同,即name  
  2. $lock->lock();  
  3. //logic here  
  4. $lock->unlock();  
相关文章
|
10天前
|
监控 PHP 数据库
【PHP开发专栏】PHP事务处理与并发控制
【4月更文挑战第29天】本文探讨了PHP中事务处理和并发控制的核心概念。事务处理确保数据完整性和一致性,具备ACID属性。PHP通过MySQLi和PDO扩展支持事务,示例展示了如何开启、提交和回滚事务。并发控制关注多用户环境下的数据一致性,涉及乐观锁和悲观锁策略。选择合适的事务隔离级别、避免长时间锁定、利用乐观锁以及监控调优是关键实践。理解这些原理有助于优化数据库应用的性能和稳定性。
|
存储 缓存 分布式计算
如何使用PHP处理大规模的并发请求?底层原理是什么?
如何使用PHP处理大规模的并发请求?底层原理是什么?
|
数据采集 网络协议 PHP
如何使用PHP的swoole扩展提高服务器并发能力
PHP的swoole扩展是一个高性能的网络通信框架,它可以让PHP开发者轻松地创建TCP/HTTP服务,来响应客户端的请求。但是,有些请求可能涉及到一些复杂和耗时的业务逻辑,如果在工作进程中直接处理,可能会影响服务器的并发能力。
155 0
如何使用PHP的swoole扩展提高服务器并发能力
|
Unix API PHP
PHP如何实现多进程并发?底层原理是什么?
PHP如何实现多进程并发?底层原理是什么?
153 0
|
PHP UED
PHP的并发能力是什么意思?底层原理是什么?
PHP的并发能力是什么意思?底层原理是什么?
174 0
|
消息中间件 NoSQL 关系型数据库
PHP 使用数据库的并发问题
在秒杀,抢购等并发场景下,可能会出现超卖的现象; 如:我们一共只有100个商品,在最后一刻,我们已经消耗了99个商品,仅剩最后一个。这个时候,系统发来多个并发请求,这批请求读取到的商品余量都是1个,然后都通过了这一个余量判断,最终导致超发。
111 0
|
Ubuntu 应用服务中间件 测试技术
php + nginx 网站并发压力测试及优化
测试工具: Apache 压力测试工具ab ab是针对apache的性能测试工具,可以只安装ab工具。 ubuntu安装ab
php + nginx 网站并发压力测试及优化
|
SQL 关系型数据库 MySQL
php mysql 异步, php mysql 异步并发查询
php mysql 异步, php mysql 异步并发查询
174 0
|
PHP Windows 数据格式
一个PHP高性能、多并发、restful的工具库(基于multi_curl)
This is high performance curl wrapper written in pure PHP. It's compatible with PHP 5.4+ and HHVM. Notice that libcurl version must be over 7.36.0, otherwise timeout can not suppert decimal. 这是一个高性能的PHP封装的HTTP Restful多线程并发请求库,参考借鉴了httpresful 、multirequest等优秀的代码。
1221 0