PHP 文件锁与进程锁的使用示例


Posted in PHP onAugust 07, 2017

鉴于前面介绍了swoole,就借用swoole的服务器/客户端与多进程机制对锁进行说明.

这里只针对PHP的锁机制进行说明,由于SQL的锁与其作用方式和应用场景不同,将作另行说明.

1.文件锁

  • flock()
  • fclose()
  • swoole_lock()

文件锁的可能应用场景为:

1.限制并发多进程或多台服务器需要对同一文件进行访问和修改;

2.对参与文件I/O的进程队列化和人为阻塞;

3.在业务逻辑中对文件内容进行守护;

下面是文件锁C/S通讯机制下的使用,已经省略了具体的通讯过程

Server(服务器通讯过程已略):

//监听数据发送事件
$serv->on('receive', function ($serv, $fd, $from_id, $data) {
  $serv->send($fd, "ServerEnd");

  $p_file = "locktest.txt";
  var_dump(file_get_contents($p_file));
});

Client1(服务器通讯过程已略):

$s_recv = "ww";

$p_file = "locktest.txt";

$o_file = fopen($p_file,'w+');
// flock()加锁方式:
flock($o_file,LOCK_EX);

// // swoole加锁方式:
// $lock = new swoole_lock(SWOOLE_FILELOCK, $p_file);
// $lock->lock();

fwrite($o_file, 'ss' . $s_recv);

sleep(30);
// 两种解锁方式
// flock($o_file, LOCK_UN);
// $lock->unlock();

Client2(服务器通讯过程已略):

$s_recv = "xx";

$p_file = "locktest.txt";

$o_file = fopen($p_file,'w+');
// flock()加锁方式:
flock($o_file,LOCK_EX);

// // swoole加锁方式:
// $lock = new swoole_lock(SWOOLE_FILELOCK, $p_file);
// $lock->lock();


fwrite($o_file, 'ss' . $s_recv);

// 两种解锁方式
// flock($o_file, LOCK_UN);
// $lock->unlock();

结果:

Client2被阻塞了30s,直到Client1执行结束才对文件进行了一次写入;

[l0.16@4 m29.5% c30s04] $ php swoole_client2.php

需要注意的是:

1.无论是flock()还是swoole提供的swoole_lock(),都有在进程结束时自动解锁的机制,所以在demo中即使不进行手动解锁也能正常运行,因此这里在第一个Client中执行了sleep()暂停函数来观察文件锁的效果;

2.flock()的标准释放方式为flock($file,LOCK_UN);, 但是个人喜欢fclose(),永绝后患;

2.进程锁

与文件锁不同的是,进程锁并不用于阻止对文件的I/O,而是用于防止多进程并发造成的预期之外的后果.所以需要在多进程并发时将其队列化,即在某进程的关键逻辑执行结束前阻塞其他并发进程的逻辑执行.

实现思路有几种:

1.利用flock()文件锁,创建一个临时lock文件,使用LOCK_NB模拟阻塞或非阻塞流,再在进程内部使用判定条件控制逻辑执行;

非阻塞模型demo:

$p_file = "locktest.txt";
$o_file = fopen($p_file, 'w+');

// 如果临时文件被锁定,这里的flock()将返回false
if (!flock($o_file, LOCK_EX + LOCK_NB)) {
  var_dump('Process Locked');
}
else {
  // 非阻塞模型必须在flock()中增加LOCK_NB参数
  // 当然,这里取消LOCK_NB参数就是阻塞模型了
  flock($o_file, LOCK_EX + LOCK_NB);
  var_dump('Process Locking');
  // 模拟长时间的执行操作
  sleep(10);
}

2.利用swoole提供的共享内存,缓存方法或通信方法在不同的进程中传递一个全局变量,进程获取该变量的状态后使用判定条件控制逻辑执行;

传递变量的方法很多,这里只提供一个思路,就以memcached为例;

阻塞模型demo:

// 初始化memcached
$memcached = new Memcache;
$memcached->connect("localhost", 11211);

// 获取用来做状态判定的全局变量
$s_flag = $memcached->get("flag");

if (!$s_flag) {
  // 这里利用了memcached的过期时间作为演示,实际上业务处理完成后销毁该变量即可
  $memcached->set("flag", "locked", 0, 10);
  main();
}
else {
  // 阻塞模型
  while ($s_flag == 'locked') {
    var_dump('Process locked, retrying...');
    // 设置重试时间, 避免过于频繁的操作尝试
    sleep(1);
    // 更新状态变量
    $s_flag = $memcached->get("flag");
  }
  // // 非阻塞模型
  // if ($s_flag == 'locked') {
  //   var_dump('Process locked, suspended');
  //   die();
  // }
  main();
}

// 模拟业务主函数
function main() {
  var_dump('Process Running');
  // 业务执行结束后回收memcached
  // $memcached->delete("flag");
}

这里需要注意的是:

1.memcached的过期时间不可少于程序运行的实际时间,因此建议稍微长一点,逻辑执行结束后进行回收;

2.在非阻塞模型中,若状态被判定为false,应该将进程中止或block,避免业务逻辑的继续执行;

3.在实际应用中,设置一个重试时间很有必要,这样可以很大程度上减少针对memcached的大量I/O并发,减轻服务器压力;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP网站提速三大“软”招
Oct 09 PHP
php横向重复区域显示二法
Sep 25 PHP
PHP导入Excel到MySQL的方法
Apr 23 PHP
php中取得文件的后缀名?
Feb 20 PHP
深入php socket的讲解与实例分析
Jun 13 PHP
解析php取整的几种方式
Jun 25 PHP
php 强制下载文件实现代码
Oct 28 PHP
php+xml实现在线英文词典查询的方法
Jan 23 PHP
浅谈PHP拦截器之__set()与__get()的理解与使用方法
Oct 18 PHP
php输出反斜杠的实例方法
Sep 19 PHP
PHP 图片合成、仿微信群头像的方法示例
Oct 25 PHP
WordPress免插件实现面包屑导航的示例代码
Aug 20 PHP
PHP实现找出有序数组中绝对值最小的数算法分析
Aug 07 #PHP
php基于session锁防止阻塞请求的方法分析
Aug 07 #PHP
在Yii2特定页面如何禁用调试工具栏Debug Toolbar详解
Aug 07 #PHP
PHP编程中的Session阻塞问题与解决方法分析
Aug 07 #PHP
PHP基于IMAP收取邮件的方法示例
Aug 07 #PHP
PHP与JavaScript针对Cookie的读写、交互操作方法详解
Aug 07 #PHP
php+javascript实现的动态显示服务器运行程序进度条功能示例
Aug 07 #PHP
You might like
MySQL中create table语句的基本语法是
2007/01/15 PHP
php中防止伪造跨站请求的小招式
2011/09/02 PHP
浏览器预览PHP文件时顶部出现空白影响布局分析原因及解决办法
2013/01/11 PHP
php选择排序法实现数组排序实例分析
2015/02/16 PHP
PHP简单实现遍历目录下特定文件的方法小结
2017/05/22 PHP
提高网站性能之 如何对待JavaScript
2009/10/31 Javascript
JS输入用户名自动显示邮箱后缀列表的方法
2015/01/27 Javascript
jQuery DOM插入节点操作指南
2015/03/03 Javascript
jquery+html5制作超酷的圆盘时钟表
2015/04/14 Javascript
JS实现超精简的链接列表在固定区域内滚动效果代码
2015/11/04 Javascript
javascript设置和获取cookie的方法实例详解
2016/01/05 Javascript
Angular.js 实现数字转换汉字实例代码
2016/07/14 Javascript
Bootstrap 模态对话框只加载一次 remote 数据的完美解决办法
2017/07/09 Javascript
js实现方块上下左右移动效果
2017/08/17 Javascript
微信小程序 按钮滑动的实现方法
2017/09/27 Javascript
nodejs连接mysql数据库及基本知识点详解
2018/03/20 NodeJs
echarts设置图例颜色和地图底色的方法实例
2018/08/01 Javascript
微信小程序module.exports模块化操作实例浅析
2018/12/20 Javascript
Vue2.0 $set()的正确使用详解
2020/07/28 Javascript
Python sys.path详细介绍
2013/10/17 Python
python3读取csv和xlsx文件的实例
2018/06/22 Python
对python中的iter()函数与next()函数详解
2018/10/18 Python
Python GUI学习之登录系统界面篇
2019/08/21 Python
python实现通过flask和前端进行数据收发
2019/08/22 Python
python 五子棋如何获得鼠标点击坐标
2019/11/04 Python
python 解决Windows平台上路径有空格的问题
2020/11/10 Python
pytorch中index_select()的用法详解
2021/01/06 Python
一款纯css3实现的tab选项卡的实列教程
2014/12/11 HTML / CSS
详解使用HTML5的classList属性操作CSS类
2017/10/13 HTML / CSS
八年级音乐教学反思
2014/01/09 职场文书
劳动竞赛活动方案
2014/02/20 职场文书
优秀员工推荐信
2014/05/10 职场文书
本科生导师推荐信范文
2014/05/18 职场文书
创业计划书之酒店
2019/08/30 职场文书
MySQL 存储过程的优缺点分析
2021/05/20 MySQL
Go微服务项目配置文件的定义和读取示例详解
2022/06/21 Golang