Swoole

repository·master·Indexed 12 days ago

https://github.com/swoole/swoole-src

An event-driven, asynchronous, coroutine-based concurrency library for PHP designed for high performance. It enables the creation of high-performance HTTP, WebSocket, and TCP servers, and provides coroutine clients for MySQL, Redis, and HTTP. Swoole features runtime hooks that convert standard blocking PHP functions into non-blocking I/O, supporting extensions like ext-curl, ext-redis, and PDO.

Tokens
16.4K
Snippets
45
Records
75
Agent score
97%

What's inside Swoole

  1. Use the standalone pdo_oci PECL package

    master

    Starting from PHP 8.4, the pdo_oci extension has been removed from the PHP core and migrated to a standalone PECL package. If you require the version maintained by the PHP core (which includes specific modifications made in May 2025), note that the current PECL version (1.1.0) may differ from the core implementation.

  2. Use the Hiredis Asynchronous API

    master

    Hiredis provides an asynchronous API designed to work with event libraries (like libev or libevent). It uses a non-blocking connection model where commands are automatically pipelined.

    Key Concepts:

    • Non-blocking Connection: redisAsyncConnect returns a redisAsyncContext immediately. You must check the err field to verify if the connection attempt was successful.
    • Thread Safety: A redisAsyncContext is not thread-safe.
    • Lifecycle: The context object is automatically freed after the disconnect callback is executed.
    • Event Loop Integration: To use Hiredis with an event library, you must set specific hooks on the context object after creation (refer to adapters/ for libev and libevent implementations).
    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        printf("Error: %s\n", c->errstr);
        // handle error
    }
  3. How the IOCP Readiness Bridge works for cURL

    master

    To bridge the completion-based IOCP API with libcurl's readiness-based curl_multi_socket_action() API, Swoole performs the following:

    1. Socket Monitoring: libcurl invokes CURLMOPT_SOCKETFUNCTION to request monitoring for specific events (CURL_POLL_IN, CURL_POLL_OUT, etc.).
    2. Probe Submission: Swoole submits zero-length overlapped operations to the socket:
      • Read Interest: WSARecv with a zero-length WSABUF.
      • Write Interest: WSASend with a zero-length WSABUF.
    3. Completion Handling: When the IOCP dispatcher receives a completion packet, it records the corresponding event bit (CURL_CSELECT_IN, CURL_CSELECT_OUT, or CURL_CSELECT_ERR) and resumes the coroutine.
    4. Actual I/O: The resumed coroutine calls selector_finish(), which triggers curl_multi_socket_action(). libcurl then performs the real data transfer.

    Note on Data Integrity: Because the probes use zero-byte buffers, no payload data is intercepted or corrupted by Swoole; libcurl remains the sole authority for reading and writing application bytes.

    // Example of zero-byte probe buffers used by Swoole
    WSABUF buffer;
    buffer.buf = &dummy;
    buffer.len = 0;
    
    // For read interest
    WSARecv(sockfd, &buffer, 1, &bytes, &flags, &overlapped, nullptr);
    
    // For write interest
    WSASend(sockfd, &buffer, 1, &bytes, 0, &overlapped, nullptr);
  4. Understand Swoole support lifecycles

    master

    Swoole defines two types of support for its releases:

    1. Active support: The release is actively maintained. This includes regular point releases and fixes for reported bugs and security issues.
    2. Security fixes only: The release is only maintained for critical security issues. Updates are made on an as-needed basis rather than through regular release cycles.
  5. Transform synchronous PHP libraries into coroutines

    master

    Since Swoole v4.1.0, you can transform synchronous PHP network libraries (like php-redis, PDO, mysqli, or standard stream functions) into asynchronous coroutine-friendly libraries using a single method call.

    By calling Swoole\Runtime::enableCoroutine() at the very top of your script, the Swoole kernel replaces ZendVM stream function pointers. This allows socket operations in php_stream based extensions to be dynamically converted to asynchronous IO scheduled by the coroutine runtime.

    Supported operations include:

    • Network IO (TCP/UDP/Unix sockets)
    • File IO (read, write, delete)
    • Database communication (PDO, MySQLi)
    • Standard PHP functions like usleep, file_get_contents, and stream_socket_client.
    Swoole\Runtime::enableCoroutine();
    
    Co\run(function() {
        // Now, even synchronous-looking code runs asynchronously within coroutines
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        echo $redis->get('awesome');
    });
  6. How Runtime Hooks Work

    master

    Swoole hooks blocking I/O functions at the bottom layer and automatically converts them to non-blocking functions. This allows standard PHP blocking functions to be called concurrently within coroutines without stalling the entire process.

    To enable this, use $server->set(['hook_flags' => SWOOLE_HOOK_ALL]); or similar configuration.

  7. Use Channels for Coroutine Communication

    master

    A Swoole\Coroutine\Channel is the primary mechanism for exchanging data between coroutines, following the CSP (Communicating Sequential Processes) programming model.

    Common use cases include:

    • Connection Pools: Managing a fixed set of resources (like Redis connections) to prevent overloading the server.
    • Producer/Consumer Patterns: Coordinating multiple coroutines to perform tasks and collect results efficiently.
  8. Customize Redis reply objects

    master

    When using the redisReader API, you can customize how redisReply objects are instantiated. This is useful for creating language-specific objects (e.g., Ruby or Python objects) directly from the parser.

    To do this, set the fn field on the redisReader struct immediately after calling redisReaderCreate().

  9. Use the Hiredis Synchronous API

    master

    The synchronous API allows for straightforward command execution. The core workflow involves:

    1. Creating a redisContext via redisConnect.
    2. Issuing commands using redisCommand or redisCommandArgv.
    3. Processing the redisReply object.
    4. Cleaning up the reply with freeReplyObject and the context with redisFree.

    Note: A redisContext is not thread-safe.

    redisContext *redisConnect(const char *ip, int port);
    void *redisCommand(redisContext *c, const char *format, ...);
    void freeReplyObject(void *reply);
  10. Understand the Windows IOCP cURL Runtime Design

    master

    Swoole's native cURL coroutine runtime on Windows uses an IOCP Readiness Bridge rather than a full data-path transport.

    Key Concepts:

    • Ownership: libcurl retains full ownership of the transfer state machine, including TLS state, HTTP/1.1/2 protocols, proxy negotiation, and actual socket I/O (reads/writes).
    • Mechanism: Swoole uses Windows overlapped I/O and IOCP to act as a readiness adapter. It submits zero-byte WSARecv and WSASend operations to trigger IOCP completion packets.
    • Flow: When an IOCP completion is received, Swoole does not consume payload data. Instead, it uses the completion as a signal to resume the bound coroutine, which then calls curl_multi_socket_action() to let libcurl perform the actual I/O.
    • Purpose: This design allows Swoole to use its existing IOCP reactor for coroutine scheduling on Windows without re-implementing the complex HTTP/TLS stack.
  11. Understand Swoole Coroutines

    master

    Swoole 4.x+ provides built-in coroutines that allow you to write fully synchronized, synchronous-looking PHP code that achieves asynchronous performance. The underlying coroutine scheduler handles the switching automatically without requiring additional keywords in your PHP code.

    Coroutines are ultra-lightweight threads, enabling you to spawn thousands of them within a single process to handle high concurrency.