二十三、Swoole 基础学习笔记 - Swoole 进程间锁 Lock

作者: 温新

分类: 【Swoole 系列】

阅读: 1192

时间: 2023-03-13 11:49:30

hi,我是温新,一名PHPer

文章基于 Swoole 5.0.1 版本编写。

**学习目标:学习并了解 Lock 的使用 **

说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!

说起锁,PHP 中有锁,MySQL 中有锁...锁在多进程、多线程操作中有着至关重要的作用。比如有两个进程同时要修改 $num=1 的值,进程一要修改为 5,进程二要修改为10,那么$num 最后的值会是多少?这个结果无法确定。可以通过加锁来确保同时只有一个进程对资源进程操作,操作完成后才有由其他进程操作。

Swoole Lock

PHP 代码中可以很方便地创建一个锁,用来实现数据同步。Lock 类支持 5 种锁的类型:

锁类型 说明
SWOOLE_MUTEX 互斥锁
SWOOLE_RWLOCK 读写锁
SWOOLE_SPINLOCK 自旋锁
<?php
// 23-swoole-lock.php

$lock = new Swoole\Lock();

$pool = new Swoole\Process\Pool(3, SWOOLE_IPC_NONE, 0, true);

$pool->on('Workerstart', function ($pool, $workerId) use ($lock) {
	echo 'Worker ' . $workerId . '执行 ' . PHP_EOL;
    // 加锁
	$lock->lock();
	echo 'Worker ' . $workerId . ' 获得锁 ' . microtime(true) . PHP_EOL;
	sleep(3);
    // 释放锁
	$lock->unlock();
	echo 'Worker ' . $workerId . ' 退出 ' . PHP_EOL;

});

$pool->start();

代码解析:

  • 在这一段代码中,使用 3 个进程执行任务;
  • 第一个进程进来之后进行加锁,加锁后,其他进程进程会阻塞,知道持有锁的进程执行完成。

执行结果:

$php 23-swoole-lock-1.php 
Worker 0 执行
Worker 0 获得锁 1673273562.803
Worker 1 执行
Worker 2 执行
Worker 0 退出 
Worker 1 获得锁 1673273565.8035
Worker 0 执行

结果分析:

  • 0 ,Worker 0 进来后,获得锁,Worker 1 和 2 出现阻塞操作;
  • 3 秒后,Worker 0 执行完成,然后 Worker 获得锁,然后其他 Worker 继续阻塞。

Lock 相关方法

__contruct

/**
* @param int $type 锁的类型
* @param string $lockfile 指定文件锁的路径【当类型为 SWOOLE_FILELOCK 时必须传入】
**/
Swoole\Lock::__construct(int $type = SWOOLE_MUTEX, string $lockfile = '');

注意:

1、不要循环创建 / 销毁锁的对象,否则会发生内存泄漏;

2、每一种类型的锁支持的方法都不一样。如读写锁、文件锁可以支持 $lock->lock_read()。另外除文件锁外,其他类型的锁必须在父进程内创建,这样 fork 出的子进程之间才可以互相争抢锁。

lock

含义:加锁操作。如果有其他进程持有锁,那这里将进入阻塞,直到持有锁的进程 unlock() 释放锁。

Swoole\Lock->lock(): bool

unlock

含义:释放锁。

Swoole\Lock->unlock(): bool

lock_read

含义:只读加锁。

Swoole\Lock->lock_read(): bool
  • 在持有读锁的过程中,其他进程依然可以获得读锁,可以继续发生读操作;
  • 但不能 $lock->lock()$lock->trylock(),这两个方法是获取独占锁,在独占锁加锁时,其他进程无法再进行任何操作,包括读锁;
  • 当另一个进程获得独占锁 (调用 $lock->lock()/$lock->trylock()) 时,$lock->lock_read() 会发生阻塞,直到持有独占锁的进程释放锁。

只有 SWOOLE_RWLOCKSWOOLE_FILELOCK 类型的锁支持只读加锁

trylock_read()

含义:加锁。此方法与 lock_read() 相同,但是非阻塞的。

Swoole\Lock->trylock_read(): bool

调用会立即返回,必须检测返回值以确定是否拿到了锁。

lockwait

含义:加锁操作。作用与 lock() 方法一致,但 lockwait() 可以设置超时时间。

/**
* @param float $timeout 指定超时时间
* 
* @return 1、在规定的时间内未获得锁,返回 false
*		  2、加锁成功返回 true
**/
Swoole\Lock->lockwait(float $timeout = 1.0): bool

本篇文章学习了 Lock 的值,下篇文章继续学习 Swoole。

请登录后再评论