zoukankan      html  css  js  c++  java
  • PHP 进程锁定问题

    今天看了一个 PHP 进程锁定的文章,

    http://www.cnblogs.com/sunli/archive/2009/11/24/1609553.html

    刚好,前几天也写了一个 进程锁定的类,这个类要比上面的文章里面提到的更加强大一写。

    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 消息队列中 http://www.cnblogs.com/niniwzw/archive/2009/11/17/1604677.html

    就可以实现 线程安全的消息队列。

  • 相关阅读:
    SpringMVC集成Swagger插件以及Swagger注解的简单使用
    Java后台直接生成二维码介绍
    Java条形码生成技术-Barcode4j
    对Java Serializable(序列化)的理解和总结(一)
    java下划线与驼峰命名互转
    Mybatis实战之TypeHandler高级进阶
    迪卡侬女主(视频) 第一集
    MySQL优化(五)
    PDO连接mysql和pgsql数据库
    MySQL的FIND_IN_SET()函数
  • 原文地址:https://www.cnblogs.com/niniwzw/p/1609598.html
Copyright © 2011-2022 走看看