• 技术文章 >后端开发 >php教程

    PHP 进程锁定问题分析研究_PHP

    2016-06-01 12:22:21原创264
    1. 区分读锁定 和 写 锁定。
    如果每次都使用 写锁定,那么连多个进程读取一个文件也要排队,这样的效率肯定不行。
    2. 区分 阻塞 与 非 阻塞模式。
    一般来说,如果一个进程在写一个文件的时候,另外一个进程应该被阻塞,但是,很多时候,我们可以先干点别的事情,
    然后再判断一下是否有其他人在写文件,如果没有,再加入数据,这样的效率更高。
    3. 修复了 锁定文件在linux 上的bug,特别是 在 gfs 文件系统上的bug。
    代码如下:
    复制代码 代码如下:
    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("//m.sbmmt.com/m/", "\\"), array("_", "_"), $this->name);
    if ($config_file_lock_path == null) {
    $this->name = dirname(__FILE__) . "/lock/" . $this->name;
    } else {
    $this->name = $config_file_lock_path . "//m.sbmmt.com/m/" . $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;
    }
    }
    }
    ?>

    测试代码:
    复制代码 代码如下:
    /**
    * 进行写锁定的测试
    * 打开线程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 消息队列中就可以实现 线程安全的消息队列。
    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:PHP 进程锁定
    上一篇:PHP MYSQL乱码问题,使用SET NAMES utf8校正_PHP 下一篇:在mysql数据库原有字段后增加新内容_PHP
    Web大前端开发直播班

    相关文章推荐

    • 十天学会php之第三天_php基础• php截取字符串函数分享_PHP• php中session与cookie的比较_PHP• php实现webservice实例_PHP• php将csv文件导入到mysql数据库的方法_PHP

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网