二十三、Swoole 基础学习笔记 - Swoole 进程间锁 Lock
hi,我是温新,一名PHPer
文章基于 Swoole 5.0.1 版本编写。
学习目标:学习并了解 Lock 的使用
说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!
锁
说起锁,PHP 中有锁,MySQL 中有锁...锁在多进程、多线程操作中有着至关重要的作用。比如有两个进程同时要修改 $num=1
的值,进程一要修改为 5
,进程二要修改为10
,那么$num
最后的值会是多少?这个结果无法确定。可以通过加锁来确保同时只有一个进程对资源进程操作,操作完成后才有由其他进程操作。
Swoole Lock
PHP
代码中可以很方便地创建一个锁,用来实现数据同步。Lock
类支持 5
种锁的类型:
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 23-swoole-lock.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$lock</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">new</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Lock</span>();</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$pool</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">new</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Process\Pool</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">3</span>, <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">SWOOLE_IPC_NONE</span>, <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">0</span>, <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">true</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$pool</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">on</span>(<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'Workerstart'</span>, <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> (<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$pool</span>, <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$workerId</span>) <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">use</span> (<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$lock</span>) {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'Worker '</span> . <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$workerId</span> . <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'执行 '</span> . <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">PHP_EOL</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 加锁</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$lock</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">lock</span>();</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'Worker '</span> . <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$workerId</span> . <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">' 获得锁 '</span> . <span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">microtime</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">true</span>) . <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">PHP_EOL</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">sleep</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">3</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 释放锁</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$lock</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">unlock</span>();</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'Worker '</span> . <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$workerId</span> . <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">' 退出 '</span> . <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">PHP_EOL</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">});</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$pool</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">start</span>();</span>
代码解析:
- 在这一段代码中,使用 3 个进程执行任务;
- 第一个进程进来之后进行加锁,加锁后,其他进程进程会阻塞,知道持有锁的进程执行完成。
执行结果:
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$php</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">23</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">-swoole-lock-1</span>.php </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Worker <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">0</span> 执行</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Worker <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">0</span> 获得锁 <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1673273562</span>.803</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Worker <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1</span> 执行</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Worker <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">2</span> 执行</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Worker <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">0</span> 退出 </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Worker <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1</span> 获得锁 <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1673273565</span>.8035</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Worker <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">0</span> 执行</span>
结果分析:
- 0 ,Worker 0 进来后,获得锁,Worker 1 和 2 出现阻塞操作;
- 3 秒后,Worker 0 执行完成,然后 Worker 获得锁,然后其他 Worker 继续阻塞。
Lock 相关方法
__contruct
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">/**</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">* @param int $type 锁的类型</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">* @param string $lockfile 指定文件锁的路径【当类型为 SWOOLE_FILELOCK 时必须传入】</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">**/</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Lock</span>::<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">__construct</span>(<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">int</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$type</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">SWOOLE_MUTEX</span>, <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">string</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$lockfile</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">''</span>);</span>
注意:
1、不要循环创建 / 销毁锁的对象,否则会发生内存泄漏;
2、每一种类型的锁支持的方法都不一样。如读写锁、文件锁可以支持
$lock->lock_read()
。另外除文件锁外,其他类型的锁必须在父进程内创建,这样fork
出的子进程之间才可以互相争抢锁。
lock
含义:加锁操作。如果有其他进程持有锁,那这里将进入阻塞,直到持有锁的进程 unlock()
释放锁。
<span style="color: rgb(0, 176, 240);">Swoole\Lock->lock(): bool</span><br></br>
unlock
含义:释放锁。
<span style="color: rgb(0, 176, 240);">Swoole\Lock->unlock(): bool</span><br></br>
lock_read
含义:只读加锁。
<span style="color: rgb(0, 176, 240);">Swoole\Lock->lock_read(): bool</span><br></br>
- 在持有读锁的过程中,其他进程依然可以获得读锁,可以继续发生读操作;
- 但不能
$lock->lock()
或$lock->trylock()
,这两个方法是获取独占锁,在独占锁加锁时,其他进程无法再进行任何操作,包括读锁; - 当另一个进程获得独占锁 (调用
$lock->lock()
/$lock->trylock()
) 时,$lock->lock_read()
会发生阻塞,直到持有独占锁的进程释放锁。
只有
SWOOLE_RWLOCK
和SWOOLE_FILELOCK
类型的锁支持只读加锁
trylock_read()
含义:加锁。此方法与 lock_read()
相同,但是非阻塞的。
<span style="color: rgb(0, 176, 240);">Swoole\Lock->trylock_read(): bool</span><br></br>
调用会立即返回,必须检测返回值以确定是否拿到了锁。
lockwait
含义:加锁操作。作用与 lock()
方法一致,但 lockwait()
可以设置超时时间。
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">/**</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">* @param float $timeout 指定超时时间</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">* </span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">* @return 1、在规定的时间内未获得锁,返回 false</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">* 2、加锁成功返回 true</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">**/</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Lock</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">lockwait</span>(<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">float</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$timeout</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1.0</span>): <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">bool</span></span>
本篇文章学习了 Lock 的值,下篇文章继续学习 Swoole。
请登录后再评论