PHP 进程锁定问题分析研究
PHP 进程锁定问题分析研究
发布时间:2016-12-29 来源:查字典编辑
摘要:1.区分读锁定和写锁定。如果每次都使用写锁定,那么连多个进程读取一个文件也要排队,这样的效率肯定不行。2.区分阻塞与非阻塞模式。一般来说,如...

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 消息队列中就可以实现 线程安全的消息队列。

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新php教程学习
热门php教程学习
编程开发子分类