(No version information available, might only be in Git)
В Swoole 6.0.1 для корутин, или сопрограмм, появились блокировки, которые поддерживают разделение между процессами или между потоками. Неблокирующее поведение таких блокировок повышает эффективность синхронизации корутин в многопроцессных и многопоточных средах.
При компиляции с параметром --enable-iouring
и при поддержке ядром Linux
функции io_uring futex
сопрограммная блокировка модуля Swoole реализует синхронизацию
через фьютекс io_uring
. При такой синхронизации сопрограммы ожидают пробуждения блокировки
через эффективный механизм организации очередей, который значительно повышает производительность.
Без фьютекса io_uring
корутинная блокировка переключается на механизм экспоненциально нарастающего ожидания,
при котором время ожидания увеличивается на 2^n миллисекунд, где n — количество отказов,
после каждой неудачной попытки захватить блокировку. Хотя такой подход исключает активное ожидание,
он создаёт дополнительную нагрузку на планировщик процессов и увеличивает задержки.
Сопрограммная блокировка реентерабельна — разрешает повторный вход в критическую секцию, или, говоря по-другому, рекурсивный захват блокировки, поэтому разрешает текущей удерживающей сопрограмме безопасно выполнять повторные операции блокировки.
Лучше не создавать блокировки в callback-функциях наподобие onReceive
,
поскольку это приведёт к неконтролируемому росту потребления памяти или даже вызовет утечки памяти.
Захват и освобождение блокировки выполняют в той же сопрограмме, иначе нарушается логика работы программы.
Пример #1 Базовый пример работы с блокировками
<?php
use Swoole\Coroutine\Lock;
use Swoole\Coroutine\WaitGroup;
use function Swoole\Coroutine\go;
use function Swoole\Coroutine\run;
$lock = new Lock();
$waitGroup = new WaitGroup();
run(function() use ($lock, $waitGroup) {
go(function() use ($lock, $waitGroup) {
$waitGroup->add();
$lock->lock();
sleep(1);
$lock->unlock();
$waitGroup->done();
});
go(function() use ($lock, $waitGroup) {
$waitGroup->add();
$lock->lock(); // Дождаться, пока другая сопрограмма освободит блокировку
sleep(1);
$lock->unlock();
$waitGroup->done();
});
echo 'Блокировка приостанавливает только текущую корутину, но не останавливает весь процесс';
$waitGroup->wait();
});