Swoole is an event-driven, asynchronous, coroutine-based concurrency library with high performance for PHP. ⚙️ Quick Start Run Swoole program by Docker > For details on how to use it, see:…
Swoole is an event-driven, asynchronous, coroutine-based concurrency library with high performance for PHP.












⚙️ Quick Start
Run Swoole program by Docker
bash
docker run --rm phpswoole/swoole "php --ri swoole"
> For details on how to use it, see: How to Use This Image.
Documentation
HTTP Service
php
$http = new Swoole\Http\Server('127.0.0.1', 9501);
$http->set(['hook_flags' => SWOOLE_HOOK_ALL]);
$http->on('request', function ($request, $response) {
$result = [];
Co::join([
go(function () use (&$result) {
$result['google'] = file_get_contents("https://www.google.com/");
}),
go(function () use (&$result) {
$result['taobao'] = file_get_contents("https://www.taobao.com/");
})
]);
$response->end(json_encode($result));
});
$http->start();
Concurrency
php
Co\run(function() {
Co\go(function() {
while(1) {
sleep(1);
$fp = stream_socket_client("tcp://127.0.0.1:8000", $errno, $errstr, 30);
echo fread($fp, 8192), PHP_EOL;
}
});
Co\go(function() {
$fp = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
while(1) {
$conn = stream_socket_accept($fp);
fwrite($conn, 'The local time is ' . date('n/j/Y g:i a'));
}
});
Co\go(function() {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
while(true) {
$redis->subscribe(['test'], function ($instance, $channelName, $message) {
echo 'New redis message: '.$channelName, "==>", $message, PHP_EOL;
});
}
});
Co\go(function() {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$count = 0;
while(true) {
sleep(2);
$redis->publish('test','hello, world, count='.$count++);
}
});
});
Runtime Hook
Swoole hooks the blocking io function of PHP at the bottom layer and automatically converts it to a non-blocking function, so that these functions can be called concurrently in coroutines.
Supported extension/functions
ext-curl(Supportsymfonyandguzzle)ext-redisext-mysqliext-pdo_mysqlext-pdo_pgsqlext-pdo_sqliteext-pdo_oracleext-pdo_odbcstream functions(e.g.stream_socket_client/stream_socket_server), SupportsTCP/UDP/UDG/Unix/SSL/TLS/FileSystem API/Pipeext-socketsext-soapsleep/usleep/time_sleep_untilproc_opengethostbyname/shell_exec/execfread/fopen/fsockopen/fwrite/flock
🛠 Develop & Discussion
+ __IDE Helper & API__:
+ __Twitter__:
+ __Discord__:
+ __中文社区__:
💎 Awesome Swoole
Project Awesome Swoole maintains a curated list of awesome things related to Swoole, including- Swoole-based frameworks and libraries.
- Packages to integrate Swoole with popular PHP frameworks, including Laravel, Symfony, Slim, and Yii.
- Books, videos, and other learning materials about Swoole.
- Debugging, profiling, and testing tools for developing Swoole-based applications.
- Coroutine-friendly packages and libraries.
- Other Swoole related projects and resources.
✨ Event-based
The network layer in Swoole is event-based and takes full advantage of the underlying epoll/kqueue implementation, making it really easy to serve millions of requests.
Swoole 4.x uses a brand new engine kernel and now it has a full-time developer team, so we are entering an unprecedented period in PHP history which offers a unique possibility for rapid evolution in performance.
⚡ Coroutine
Swoole 4.x or later supports the built-in coroutine with high availability, and you can use fully synchronized code to implement asynchronous performance. PHP code without any additional keywords, the underlying automatic coroutine-scheduling.
Developers can understand coroutines as ultra-lightweight threads, and you can easily create thousands of coroutines in a single process.
MySQL
Concurrency 10K requests to read data from MySQL takes only 0.2s!
php
$s = microtime(true);
Co\run(function() {
for ($c = 100; $c--;) {
go(function () {
$mysql = new Swoole\Coroutine\MySQL;
$mysql->connect([
'host' => '127.0.0.1',
'user' => 'root',
'password' => 'root',
'database' => 'test'
]);
$statement = $mysql->prepare('SELECT * FROM `user`');
for ($n = 100; $n--;) {
$result = $statement->execute();
assert(count($result) > 0);
}
});
}
});
echo 'use ' . (microtime(true) - $s) . ' s';
Mixed server
You can create multiple services on the single event loop: TCP, HTTP, Websocket and HTTP2, and easily handle thousands of requests.
php
function tcp_pack(string $data): string
{
return pack('N', strlen($data)) . $data;
}
function tcp_unpack(string $data): string
{
return substr($data, 4, unpack('N', substr($data, 0, 4))[1]);
}
$tcp_options = [
'open_length_check' => true,
'package_length_type' => 'N',
'package_length_offset' => 0,
'package_body_offset' => 4
];
php
$server = new Swoole\WebSocket\Server('127.0.0.1', 9501, SWOOLE_BASE);
$server->set(['open_http2_protocol' => true]);
// http && http2
$server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) {
$response->end('Hello ' . $request->rawcontent());
});
// websocket
$server->on('message', function (Swoole\WebSocket\Server $server, Swoole\WebSocket\Frame $frame) {
$server->push($frame->fd, 'Hello ' . $frame->data);
});
// tcp
$tcp_server = $server->listen('127.0.0.1', 9502, SWOOLE_TCP);
$tcp_server->set($tcp_options);
$tcp_server->on('receive', function (Swoole\Server $server, int $fd, int $reactor_id, string $data) {
$server->send($fd, tcp_pack('Hello ' . tcp_unpack($data)));
});
$server->start();
Coroutine clients
Whether you DNS query or send requests or receive responses, all of these are scheduled by coroutine automatically.
php
go(function () {
// http
$http_client = new Swoole\Coroutine\Http\Client('127.0.0.1', 9501);
assert($http_client->post('/', 'Swoole Http'));
var_dump($http_client->body);
// websocket
$http_client->upgrade('/');
$http_client->push('Swoole Websocket');
var_dump($http_client->recv()->data);
});
go(function () {
// http2
$http2_client = new Swoole\Coroutine\Http2\Client('localhost', 9501);
$http2_client->connect();
$http2_request = new Swoole\Http2\Request;
$http2_request->method = 'POST';
$http2_request->data = 'Swoole Http2';
$http2_client->send($http2_request);
$http2_response = $http2_client->recv();
var_dump($http2_response->data);
});
go(function () use ($tcp_options) {
// tcp
$tcp_client = new Swoole\Coroutine\Client(SWOOLE_TCP);
$tcp_client->set($tcp_options);
$tcp_client->connect('127.0.0.1', 9502);
$tcp_client->send(tcp_pack('Swoole Tcp'));
var_dump(tcp_unpack($tcp_client->recv()));
});
Channel
Channel is the only way for exchanging data between coroutines, the development combination of the Coroutine + Channel is the famous CSP programming model.
In Swoole development, Channel is usually used for implementing connection pool or scheduling coroutine concurrent.
The simplest example of a connection pool
In the following example, we have a thousand concurrently requests to redis. Normally, this has exceeded the maximum number of Redis connections setting and will throw a connection exception, but the connection pool based on Channel can perfectly schedule requests. We don't have to worry about connection overload.
php
class RedisPool
{
/**@var \Swoole\Coroutine\Channel */
protected $pool;
/**
* RedisPool constructor.
* @param int $size max connections
*/
public function __construct(int $size = 100)
{
$this->pool = new \Swoole\Coroutine\Channel($size);
for ($i = 0; $i < $size; $i++) {
$redis = new \Swoole\Coroutine\Redis();
$res = $redis->connect('127.0.0.1', 6379);
if ($res == false) {
throw new \RuntimeException("failed to connect redis server.");
} else {
$this->put($redis);
}
}
}
public function get(): \Swoole\Coroutine\Redis
{
return $this->pool->pop();
}
public function put(\Swoole\Coroutine\Redis $redis)
{
$this->pool->push($redis);
}
public function close(): void
{
$this->pool->close();
$this->pool = null;
}
}
go(function () {
$pool = new RedisPool();
// max concurrency num is more than max connections
// but it's no problem, channel will help you with scheduling
for ($c = 0; $c < 1000; $c++) {
go(function () use ($pool, $c) {
for ($n = 0; $n < 100; $n++) {
$redis = $pool->get();
assert($redis->set("awesome-{$c}-{$n}", 'swoole'));
assert($redis->get("awesome-{$c}-{$n}") === 'swoole');
assert($redis->delete("awesome-{$c}-{$n}"));
$pool->put($redis);
}
});
}
});
Producer and consumers
Some Swoole's clients implement the defer mode for concurrency, but you can still implement it flexible with a combination of coroutines and channels.
php
go(function () {
// User: I need you to bring me some information back.
// Channel: OK! I will be responsible for scheduling.
$channel = new Swoole\Coroutine\Channel;
go(function () use ($channel) {
// Coroutine A: Ok! I will show you the github addr info
$addr_info = Co::getaddrinfo('github.com');
$channel->push(['A', json_encode($addr_info, JSON_PRETTY_PRINT)]);
});
go(function () use ($channel) {
// Coroutine B: Ok! I will show you what your code look like
$mirror = Co::readFile(__FILE__);
$channel->push(['B', $mirror]);
});
go(function () use ($channel) {
// Coroutine C: Ok! I will show you the date
$channel->push(['C', date(DATE_W3C)]);
});
for ($i = 3; $i--;) {
list($id, $data) = $channel->pop();
echo "From {$id}:\n {$data}\n";
}
// User: Amazing, I got every information at earliest time!
});
Timer
php
$id = Swoole\Timer::tick(100, function () {
echo "⚙️ Do something...\n";
});
Swoole\Timer::after(500, function () use ($id) {
Swoole\Timer::clear($id);
echo "⏰ Done\n";
});
Swoole\Timer::after(1000, function () use ($id) {
if (!Swoole\Timer::exists($id)) {
echo "✅ All right!\n";
}
});
The way of coroutine
php
go(function () {
$i = 0;
while (true) {
Co::sleep(0.1);
echo "📝 Do something...\n";
if (++$i === 5) {
echo "🛎 Done\n";
break;
}
}
echo "🎉 All right!\n";
});
🔥 Amazing runtime hooks
As of Swoole v4.1.0, we added the ability to transform synchronous PHP network libraries into co-routine libraries using a single line of code.
Simply call the Swoole\Runtime::enableCoroutine() method at the top of your script. In the sample below we connect to php-redis and concurrently read 10k requests in 0.1s:
php
Swoole\Runtime::enableCoroutine();
$s = microtime(true);
Co\run(function() {
for ($c = 100; $c--;) {
go(function () {
($redis = new Redis)->connect('127.0.0.1', 6379);
for ($n = 100; $n--;) {
assert($redis->get('awesome') === 'swoole');
}
});
}
});
echo 'use ' . (microtime(true) - $s) . ' s';
By calling this method, the Swoole kernel replaces ZendVM stream function pointers. If you use php_stream based extensions, all socket operations can be dynamically converted to be asynchronous IO scheduled by coroutine at runtime!
How many things you can do in 1s?
Sleep 10K times, read, write, check and delete files 10K times, use PDO and MySQLi to communicate with the database 10K times, create a TCP server and multiple clients to communicate with each other 10K times, create a UDP server and multiple clients to communicate with each other 10K times... Everything works well in one process!
Just see what the Swoole brings, just imagine...
``php
Swoole\Runtime::enableCoroutine();
$s = microtime(true);
Co\run(function() {
// i just want to sleep...
for ($c = 100; $c--;) {
go(function () {
for ($n = 100; $n--;) {
usleep(1000);
}
});
}
// 10K file read and write
for ($c = 100; $c--;) {
go(function () use ($c) {
$tmp_filename = "/tmp/test-{$c}.php";
for ($n = 100; $n--;) {
$self = file_get_contents(__FILE__);
file_put_contents($tmp_filename, $self);
assert(file_get_contents($tmp_filename) === $self);
}
unlink($tmp_filename);
});
}
// 10K pdo and mysqli read
for ($c = 50; $c--;) {
go(function () {
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8', 'root', 'root');
$statement = $pdo->prepare('SELECT * FROM user');id
for ($n = 100; $n--;) {
$statement->execute();
assert(count($statement->fetchAll()) > 0);
}
});
}
for ($c = 50; $c--;) {
go(function () {
$mysqli = new Mysqli('127.0.0.1', 'root', 'root', 'test');
$statement = $mysqli->prepare('SELECT FROM user`')
…
Members
-
swoole-src ★ PINNED
🚀 Coroutine-based concurrency library for PHP
C++ ★ 19k 3d agoExplain → -
library ★ PINNED
📚 Swoole Library
PHP ★ 251 24d agoExplain → -
awesome-swoole ★ PINNED
💎 A curated list of awesome things related to Swoole.
★ 266 17d agoExplain → -
docker-swoole ★ PINNED
🏄 Official Docker Image of Swoole
Dockerfile ★ 565 2d agoExplain → -
ide-helper ★ PINNED
📘 Swoole IDE Helper
PHP ★ 519 12h agoExplain → -
swoole-cli ★ PINNED
SWOOLE-CLI is a php binary distribution composed swoole & php-core & cli & fpm and mostly of common extensions.
C ★ 249 2mo agoExplain → -
phpx
C++ wrapper for Zend API
C++ ★ 861 21h agoExplain → -
phpy
Connecting the Python and PHP ecosystems together
PHP ★ 649 4mo agoExplain → -
yasd ▣
Yet Another Swoole Debugger
PHP ★ 360 3y agoExplain → -
phpkafka
PHP Kafka client is used in PHP-FPM and Swoole. PHP Kafka client supports 50 APIs, which might be one that supports the most message types ever.
PHP ★ 278 2y agoExplain → -
swoole-wiki ▣
📖Swoole全量Markdown文档, Swoole-Doc, Swoole-Wiki
Shell ★ 263 6y agoExplain → -
grpc
💎 Grpc client based on Swoole Coroutine
PHP ★ 197 3y agoExplain → -
ext-zookeeper
🧑 Coroutine-based ZooKeeper Client for PHP
C ★ 152 11mo agoExplain → -
rfc
Swoole 提案
★ 115 11mo agoExplain → -
proxy-server
Full asynchronous proxy server can support over a large number of concurrent.
PHP ★ 85 8mo agoExplain → -
debugger
Swoole 远程调试器
PHP ★ 77 5y agoExplain → -
ext-postgresql ▣
🐘 Coroutine-based client for PostgreSQL
C++ ★ 66 3y agoExplain → -
typephp
No description.
★ 63 1mo agoExplain → -
zmq
ZeroMQ bindings for Swoole
PHP ★ 37 6y agoExplain → -
build-static-php
build static php cli runtime and php-fpm
PHP ★ 26 8d agoExplain → -
php-docker
php docker file
Dockerfile ★ 23 8mo agoExplain → -
docs
No description.
HTML ★ 14 3mo agoExplain → -
benchmark
No description.
PHP ★ 12 1d agoExplain → -
make-library
Convert PHP code to C/C++ header file
PHP ★ 5 3y agoExplain → -
assert ⑂
Assertions to validate method input/output with nice error messages.
PHP ★ 2 7y agoExplain → -
installers
swoole installers
Shell ★ 1 11mo agoExplain → -
v4.4-lts
No description.
C++ ★ 1 1y agoExplain → -
phpx-ext
phpx extension project template
C++ ★ 0 3mo agoExplain → -
golang-h2demo
No description.
Go ★ 0 4y agoExplain →
No repos match these filters.
More creators on gitmyhub
xiaolai brunosimon douglascrockford standardgalactic AlexTheAnalyst