hokoo / wp-lock
WordPress 核心锁和互斥锁的库
v1.1
2024-05-05 19:37 UTC
Requires
- php: >=7.4
Requires (Dev)
- phpunit/phpunit: ^9
- yoast/phpunit-polyfills: ^1.0
This package is auto-updated.
Last update: 2024-09-06 12:24:48 UTC
README
这之前是来自原始仓库 soulseekah/wp-lock 的分支,由 Gennady Kovshenin 创建。现在这里有一个独立的仓库,其中包括以下更改:
- 使用自定义数据库表作为 WPDB 锁的存储,允许以简单方便的方式管理锁。
- 快速:获取一个锁只需一个查询,而不是11个或更多。
- 可读性:代码具有良好的文档,易于理解。
WP Lock 的前提条件
考虑以下用户余额充值函数,该函数容易受到竞争条件的影响
// Top-up function that is not thread-safe public function topup_user_balance( $user_id, $topup ) { $balance = get_user_meta( $user_id, 'balance', true ); $balance = $balance + $topup; update_user_meta( $user_id, 'balance', $balance ); return $balance; }
尝试在16个线程中调用上述代码100次。余额将低于预期。
下面的代码是线程安全的。
// A thread-safe version of the above topup function. public function topup_user_balance( $user_id, $topup ) { $user_balance_lock = new WP_Lock( "$user_id:meta:balance" ); $user_balance_lock->acquire( WP_Lock::WRITE ); $balance = get_user_meta( $user_id, 'balance', true ); $balance = $balance + $topup; update_user_meta( $user_id, 'balance', $balance ); $user_balance_lock->release(); return $balance; }
用法
通过 Composer 在您的插件中安装 composer require hokoo/wp-lock
。
不要忘记在您的插件中包含 Composer 自动加载器并声明使用 WP_Lock
类。
use iTRON\WP_Lock; require 'vendor/autoload.php';
无超时地获取读阻塞锁。
$lock = new WP_Lock\WP_Lock( 'my-lock' ); $lock->acquire( WP_Lock::READ, true, 0 ); // do something, and then $lock->release();
public function acquire( $level = self::WRITE, $blocking = true, $expiration = 30 )
锁级别
WP_Lock::READ
- 其他进程可以获取读锁,但不能获取写锁,直到原始锁被释放。一个共享读锁。WP_Lock::WRITE
(默认)- 其他进程不能获取读或写锁,直到原始锁被释放。一个独占读写锁
阻塞策略
- 阻塞意味着进程将在这里等待,直到获取锁(5微秒的自旋锁)。
- 非阻塞锁获取不会等待其他锁被释放,但如果锁已被另一个进程获取,则立即返回 false。因此,应该检查成功。
if ( $lock->acquire( WP_Lock::READ, false, 0 ) ) { // do something, and then $lock->release(); }
超时策略
- 0秒超时意味着锁应该被释放,否则将在 php 进程完成后自动释放。
- 非零超时意味着锁可能不会手动释放,然后将在指定秒数后自动释放。
锁存在检查
您还可能想要检查是否有其他进程获取了锁,而实际上并没有尝试获取它。
$another_lock = new WP_Lock\WP_Lock( 'my-lock' ); if ( $another_lock->acquire( WP_Lock::READ, false, 0 ) ) { $lock->lock_exists( WP_Lock::READ ); // true $lock->lock_exists( WP_Lock::WRITE ); // false $another_lock->release(); } if ( $another_lock->acquire( WP_Lock::WRITE, false, 0 ) ) { $lock->lock_exists( WP_Lock::READ ); // true $lock->lock_exists( WP_Lock::WRITE ); // true $another_lock->release(); }
注意事项
在高并发设置中,您可能会从 MySQL 获取死锁错误。这是正常的。库可以优雅地处理这些错误并按需重试查询。