Текущий Swoole имеет встроенные многофункциональные компоненты сопрограммы, которые разработчики могут напрямую вызывать, чтобы быстро реализовать асинхронное и неблокирующее параллельное программирование, избавляя разработчиков от необходимости реализации соответствующего базового кода:
TCP/UDP Client:Swoole\Coroutine\Client
TCP/UDP Server:Swoole\Coroutine\Server
HTTP/WebSocket Client:Swoole\Coroutine\HTTP\Client
HTTP/WebSocket Server:Swoole\Coroutine\HTTP\Server
HTTP2 Client:Swoole\Coroutine\HTTP2\Client
Redis Client:Swoole\Coroutine\Redis
Mysql Client:Swoole\Coroutine\MySQL
PostgreSQL Client:Swoole\Coroutine\PostgreSQL
На сервере сопрограммы соответствующая версия сопрограммы клиента используется для реализации полностью асинхронного сервера, а Swoole предоставляет набор инструментов сопрограммы:Swoole\Coroutine, который предоставляет возможность получить текущий идентификатор сопрограммы, вызов отражения и т. д.
Параллельное программирование через механизм setDefer
В качестве примера мы возьмем клиентские запросы Redis и MySQL, используя приведенное вышеSwoole\Coroutine\Redis
а такжеSwoole\Coroutine\MySQL
Компоненты, которые могут реализовать асинхронные клиенты Redis и MySQL:
<?php
$server = new \Swoole\Http\Server('127.0.0.1', 9588);
$server->on('Request', function ($request, $response) {
var_dump(time());
$mysql = new Swoole\Coroutine\MySQL();
$mysql->connect([
'host' => '127.0.0.1',
'user' => 'root',
'password' => 'root',
'database' => 'laravel58',
]);
$mysql->setDefer();
$mysql->query('select sleep(3)');
var_dump(time());
$redis1 = new Swoole\Coroutine\Redis();
$redis1->connect('127.0.0.1', 6379);
$redis1->setDefer();
$redis1->set('hello', 'world');
var_dump(time());
$redis2 = new Swoole\Coroutine\Redis();
$redis2->connect('127.0.0.1', 6379);
$redis2->setDefer();
$redis2->get('hello');
$result1 = $mysql->recv();
$result2 = $redis2->recv();
var_dump($result1, $result2, time());
$response->end('Request Finish: ' . time());
});
$server->start();
Поскольку Swoole автоматически запускает сопрограмму в функциях обратного вызова TCP-сервера и HTTP-сервера, нет необходимости явно запускать сопрограмму с помощью ключевого слова go, а затем мы можем использовать компоненты сопрограммы клиента MySQL и Redis для инициирования запросов в функции обратного вызова. .
Чтобы понять принцип работы приведенного выше кода, вам нужно сначала понять механизм setDefer сопрограммы.Большинство компонентов сопрограммы поддерживают setDefer.Этот механизм может разделить интерфейс, отвечающий на запросы, на два этапа: сначала отправить данные, а затем получить одновременно результат ответа.
Поскольку в большинстве случаев «время установления соединения и отправки данных» ничтожно мало по сравнению со «временем ожидания ответа», можно просто понять, что в режиме отсрочки запросы и ответы нескольких клиентов являются одновременными. (На самом деле одновременным является только получение ответов, установление соединений и отправка запросов — последовательные).
Возьмите приведенный выше код в качестве примера, установитеsetDefer(true)
После того, как запрос инициирован через клиент Redis или MySQL, он больше не будет ждать, пока сервер вернет результат, а вернется сразу после отправки запроса.true
. После этого вы можете продолжать инициировать другие запросы Redis, MySQL и, наконец, использоватьrecv()
способ получения содержимого ответа.
Мы сохраняем приведенный выше код вcoroutine/http.php
, а затем запустите HTTP-сервер в терминале:
php coroutine/http.php
Далее сделайте запрос к серверу в Postman, и через несколько секунд вы увидите возвращенный ответ:
Первые три разаmysql
,redis1
,redis2
Время, когда три клиента инициируют запрос, можно увидеть, хотяmysql
Он будет спать 3 секунды, но параллельное выполнение трех запросов реализовано через механизм отложенного выполнения.
Параллельное программирование через подпрограммы + каналы
В дополнение к механизму setDefer, Swoole также поддерживает параллельное программирование через подпрограммы + каналы.Давайте перепишем приведенную выше реализацию кода через подпрограммы + каналы:
<?php
$server = new \Swoole\Http\Server('127.0.0.1', 9588);
$server->on('Request', function ($request, $response) {
$channel = new \Swoole\Coroutine\Channel(3);
go(function () use ($channel) {
var_dump(time());
$mysql = new Swoole\Coroutine\MySQL();
$mysql->connect([
'host' => '127.0.0.1',
'user' => 'root',
'password' => 'root',
'database' => 'laravel58',
]);
$result = $mysql->query('select sleep(3)');
$channel->push($result);
});
go(function () use ($channel) {
var_dump(time());
$redis1 = new Swoole\Coroutine\Redis();
$redis1->connect('127.0.0.1', 6379);
$result = $redis1->set('hello', 'world');
$channel->push($result);
});
go(function () use ($channel) {
var_dump(time());
$redis2 = new Swoole\Coroutine\Redis();
$redis2->connect('127.0.0.1', 6379);
$result = $redis2->get('hello');
$channel->push($result);
});
$results = [];
for ($i = 0; $i < 3; $i++) {
$results[] = $channel->pop();
}
$response->end(json_encode([
'data' => $results,
'time' => time()
]));
});
$server->start();
Мы переписываем вызовы запросов на подключение клиента MySQL и Redis, чтобы они реализовывались через три подпрограммы, и одновременно удаляем параметр setDefer, поскольку эти три подпрограммы уже вызываются одновременно. -coroutines изолированы друг от друга, поэтому мы передаемSwoole\Coroutine\Channel(т.е. канал) для реализации совместного использования данных и связи между сопрограммами, инициализировать его буферное пространство до 3, а затем ввести его в подпрограмму с помощью метода использования и передать результат ответа черезpush
Метод помещается в канал, а затем данные в канале передаются через цикл в конце функции обратного вызова onRequest сервера.pop
Метод вынимается по очереди и помещается в массив$results
, наконец прошел$response->end()
Метод возвращает результат клиенту в формате JSON.
Мы сохраняем приведенный выше код вcoroutine/http2.php
, а затем запустите новый HTTP-сервер с помощью следующей команды в терминале:
php coroutine/http2.php
Или запросите этот сервер в Postman, настройте формат ответа на JSON, и вы увидите результат следующим образом:
Поскольку запрос MySQL выполняется дольше всего, позиция является последней. На терминале, на котором запущен сервер, вы можете увидеть, что время трех распечатанных клиентских запросов точно совпадает, что указывает на то, что они выполняются одновременно:
Очевидно, что пулы соединений Redis и MySQL могут быть легко реализованы через подпрограммы + каналы.
Надеюсь, вышеизложенное поможет вам,Многие PHP-разработчики всегда будут сталкиваться с некоторыми проблемами и узкими местами, когда они будут продвинутыми. При написании слишком большого количества бизнес-кода нет чувства направления. Я не знаю, с чего начать, чтобы улучшить. Я собрал некоторую информацию, включая, но не ограничиваясь: распределенная архитектура, высокая масштабируемость, высокая производительность, высокий уровень параллелизма, настройка производительности сервера, TP6, laravel, YII2, Redis, Swoole, Swoft, Kafka, оптимизация Mysql, сценарии оболочки, Docker, микросервисы, Nginx и другие дополнительные знания. Что вам нужно, может делиться со всеми бесплатно, нужно нажать здесь PHP Advanced Architect >>> Актуальные видео и интервью с крупными заводами можно получить бесплатно