協(xié)程
協(xié)程是一種比線程更輕量級的用戶級并發(fā)機制,能夠在進程中實現(xiàn)多任務(wù)調(diào)度。它通過手動控制掛起和恢復(fù)來實現(xiàn)協(xié)程間的切換,避免了進程上下文切換的開銷。
workerman提供了一個通用的協(xié)程接口,底層自動兼容Swoole/Swow/Fiber驅(qū)動。
提示
此特性需要 workerman>=5.1.0
注意
- 協(xié)程僅支持
Swoole
Swow
Fiber
驅(qū)動 - 如果使用
Fiber
驅(qū)動時需要安裝composer require revolt/event-loop
Swoole
或者Swow
驅(qū)動可以實現(xiàn)PHP阻塞函數(shù)自動協(xié)程化,從而實現(xiàn)原來的同步代碼異步執(zhí)行- 但
Fiber
無法像Swoole
和Swow
那樣自動協(xié)程化,遇到PHP自帶的阻塞函數(shù)時會阻塞整個進程,并不會發(fā)生協(xié)程切換 - 當使用
Swoole
Swow
Fiber
驅(qū)動時,workerman
每次運行onWorkerStart
onMessage
onConnect
onClose
等回調(diào)時會自動創(chuàng)建一個協(xié)程來執(zhí)行 - 可以利用
$worker->eventLoop=xxx;
給不同worker
設(shè)置不同的協(xié)程驅(qū)動
<?php
use Workerman\Connection\TcpConnection;
use Workerman\Coroutine;
use Workerman\Events\Swoole;
use Workerman\Events\Fiber;
use Workerman\Protocols\Http\Request;
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
$worker1 = new Worker('http://0.0.0.0:8001');
$worker1->eventLoop = Swoole::class; // 使用Swoole協(xié)程
$worker1->onMessage = function (TcpConnection $connection, Request $request) {
Coroutine::create(function () {
echo file_get_contents("http://www.example.com/event/notify");
});
$connection->send('ok');
};
$worker2 = new Worker('http://0.0.0.0:8001');
$worker2->eventLoop = Fiber::class; // 使用自帶的Fiber協(xié)程
$worker2->onMessage = function (TcpConnection $connection, Request $request) {
Coroutine::create(function () {
echo file_get_contents("http://www.example.com/event/notify");
});
$connection->send('ok');
};
Worker::runAll();
協(xié)程提供的接口
interface CoroutineInterface
{
/**
* 創(chuàng)建協(xié)程并立即執(zhí)行
*/
public static function create(callable $callable, ...$data): CoroutineInterface;
/**
* 開始協(xié)程運行
*/
public function start(mixed ...$args): mixed;
/**
* 恢復(fù)協(xié)程運行
*/
public function resume(mixed ...$args): mixed;
/**
* 獲取協(xié)程id
*/
public function id(): int;
/**
* 設(shè)置協(xié)程銷毀時的回調(diào)
*/
public static function defer(callable $callable): void;
/**
* 暫停當前協(xié)程
*/
public static function suspend(mixed $value = null): mixed;
/**
* 獲取當前協(xié)程
*/
public static function getCurrent(): CoroutineInterface|Fiber|SwowCoroutine|static;
/**
* 判斷當前是否是協(xié)程環(huán)境
*/
public static function isCoroutine(): bool;
}
關(guān)于協(xié)程
優(yōu)勢
PHP引入?yún)f(xié)程后最大的作用就是可以用同步的方式編寫異步代碼,避免了回調(diào)地獄,提高了代碼的可讀性和可維護性。
協(xié)程能大幅度提升IO密集型業(yè)務(wù)的彈性,可以用較少的進程提供更大的吞吐量。
劣勢
但是引入?yún)f(xié)程后開發(fā)者需要時刻注意全局變量污染、資源競爭、第三方庫改造等問題,開發(fā)維護成本增大,心智負擔明顯增加。
引入?yún)f(xié)程后產(chǎn)生了協(xié)程創(chuàng)建、調(diào)度、銷毀、連接池等額外開銷。
通過大量壓測數(shù)據(jù)來看,在充分利用CPU的情況下,引入?yún)f(xié)程后極限性能比阻塞式IO下降約10%-20%。