Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From Generator to Fiber the Road to Coroutine in PHP

Albert Chen
December 20, 2022

From Generator to Fiber the Road to Coroutine in PHP

COSCUP 2022

Albert Chen

December 20, 2022
Tweet

More Decks by Albert Chen

Other Decks in Programming

Transcript

  1. From Generator to Fiber
    The Road to Coroutine
    in PHP
    @COSCUP 2022
    Albert Chen

    View Slide

  2. 02 Blocking and Async I/O in PHP
    Outline
    01 I/O Models in Linux
    03 What is Generator?
    04 What is Fiber in PHP 8.1?
    05 How to use Async I/O with Coroutine?
    07 Q&A
    06 Coroutines in Swoole

    View Slide

  3. Read/Write
    Read/Write
    (O_NONBLOCK)
    I/O Multiplexing
    (select/poll/epoll)
    AIO
    I/O Models in Linux
    Simplified Matrix of Linux I/O Models
    Blocking Non-Blocking
    Synchronous
    Asynchronous
    (https://developer.ibm.com/articles/l-async)

    View Slide

  4. I/O Models in Linux
    Synchronous Blocking I/O
    (https://developer.ibm.com/articles/l-async)

    View Slide

  5. I/O Models in Linux
    Synchronous Non-Blocking I/O
    (https://developer.ibm.com/articles/l-async)

    View Slide

  6. I/O Models in Linux
    Asynchronous Blocking I/O
    (https://developer.ibm.com/articles/l-async)

    View Slide

  7. I/O Models in Linux
    Asynchronous Non-Blocking I/O
    (https://developer.ibm.com/articles/l-async)

    View Slide

  8. I/O Models in Linux
    Comparison of the I/O Models
    (https://rickhw.github.io/2019/02/27/ComputerScience/IO-Models)

    View Slide


  9. select poll epoll
    Data
    Structue
    Array Link List Hash Table
    Big O O(n) O(n) O(1)
    FD Limit
    1024 (x86)
    2048 (x64)
    Unlimited Unlimited
    I/O Multiplexing
    I/O Multiplexing in Linux

    View Slide

  10. I/O Multiplexing
    I/O Multiplexing in Linux
    (http://daemonforums.org/showthread.php?t=2124)

    View Slide

  11. Blocking I/O in PHP
    All I/O functions in PHP are born to be synchronous
    Easy for developers to understand
    Less-efficient for utilization of CPU usage

    View Slide

  12. sleep file_get_contents shell_exec end
    Blocking I/O in PHP
    1s 3s 3s
    process idle
    + +
    process idle process idle
    7s
    =

    View Slide

  13. 1s worker
    1s worker
    1s worker
    Blocking I/O in PHP
    If one request takes 1s in I/O waiting
    Each worker can handle only one request and the same time
    Concurrency in PHP depends on worker numbers
    Context switch between processes are expensive!
    request
    request
    request

    View Slide

  14. Asynchronous I/O in PHP
    The simplest but worst-performant solution in PHP
    spatie/async package (needs pcntl and posix extensions)

    View Slide

  15. Asynchronous I/O in PHP
    The simplest but worst-performant solution in PHP
    spatie/async package (needs pcntl and posix extensions)
    worker
    process process
    fork
    fork

    View Slide

  16. Asynchronous I/O in PHP
    ReactPHP

    View Slide

  17. Asynchronous I/O in PHP
    ReactPHP

    View Slide

  18. Asynchronous I/O in PHP
    Amp

    View Slide

  19. Asynchronous I/O in PHP
    Amp

    View Slide

  20. Asynchronous I/O in PHP
    Async I/O Extensions in PHP
    ext-event: libevent wrapper
    ext-ev: libev wrapper
    ext-uv: libuv wrapper
    Both ReactPHP and Amp support these extensions as

    event-loop drivers

    View Slide

  21. Asynchronous I/O in PHP
    Event Loop
    Event Queue
    Stream
    Stream
    Stream
    Stream
    Stream
    Event Loop
    callbacks

    View Slide

  22. Asynchronous I/O in PHP
    Event Loop in ReactPHP

    View Slide

  23. Asynchronous I/O in PHP
    Event Loop in ReactPHP

    View Slide

  24. Generator
    Supported from PHP 5.4
    Generator provides an easy way to implement simple iterators
    Generator allows you to write code that uses foreach to iterate over

    a set of data without needing to build an array in memory
    Generator can yield as many times as it needs to provide the values

    to be iterated over
    (From official PHP manual)

    View Slide

  25. Generator
    Reading large file with Generator
    Regular Version Generator Version
    (https://clouding.city/php/generator)

    View Slide

  26. Generator
    Generators, also known as semi-coroutines, are a subset of

    coroutines
    Coroutines can control where execution continues immediately

    after they yield, while Generators cannot, instead transferring

    control back to the generator's caller
    The yield statement in a generator does not specify a coroutine

    to jump to, but rather passes a value back to a parent routine
    (From Wikipedia)

    View Slide

  27. Generators
    yield iteration
    Generator
    Producer Consumer
    Pub/Sub Pattern
    two way data transfer

    View Slide

  28. Generator
    Two Way Data Transfer in Generator
    ?
    (https://www.npopov.com/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html)

    View Slide

  29. Generator
    Two Way Data Transfer in Generator
    yield1
    ret1
    yield2
    ret2
    NULL
    the first var_dump in gen
    the var_dump of the ->send()
    again from within gen
    the return value of ->send()
    (https://www.npopov.com/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html)

    View Slide

  30. Generator
    Generator in ReactPHP's Coroutine
    (https://github.com/reactphp/async)

    View Slide

  31. Generator
    Generator in ReactPHP's Coroutine
    (https://github.com/reactphp/async/blob/4.x/src/functions.php)

    View Slide

  32. Generator
    Generator in ReactPHP's Coroutine
    (https://github.com/reactphp/async/blob/4.x/src/functions.php)

    View Slide

  33. Generator
    Generator in Amp's Coroutine
    (https://amphp.org/http-client)

    View Slide

  34. Generator
    Generator in Amp's Coroutine
    (https://github.com/amphp/amp/blob/master/lib/Coroutine.php)

    View Slide

  35. Generator
    Generator in Amp's Coroutine
    (https://github.com/amphp/amp/blob/master/lib/Coroutine.php)

    View Slide

  36. Fiber
    New feature in PHP 8.1
    Submitted and developed by Amp
    Unlike stack-less Generators, each Fiber has its own call stack,

    allowing them to be paused within deeply nested function calls
    Execution may be interrupted anywhere in the call stack using

    Fiber::suspend()
    Once suspended, execution of the fiber may be resumed with any

    value using Fiber::resume()
    (From official PHP manual)

    View Slide

  37. Fiber
    Execution in Fiber
    (https://php.watch/versions/8.1/fibers)
    Sequential Fiber

    View Slide

  38. Fiber
    Fiber Class

    View Slide

  39. Fiber
    Basic Usage
    ?

    View Slide

  40. Fiber
    Basic Usage
    fiber start
    fiber suspend
    fiber continue
    done

    View Slide

  41. Fiber
    Basic Usage
    ?

    View Slide

  42. Fiber
    Basic Usage
    start fiber 1
    end fiber 1
    start fiber 2
    end fiber 2
    done

    View Slide

  43. Fiber
    Fibers don't make blocking code
    become non-blocking magically!

    View Slide

  44. Fiber
    Basic Usage
    ?

    View Slide

  45. Fiber
    Basic Usage
    fiber start
    0
    1
    2
    3
    .........

    View Slide

  46. Fiber
    Fibers only support Cooperative Scheduling
    for I/O-bound tasks

    View Slide

  47. Fiber
    Fiber in ReactPHP
    (https://github.com/reactphp/async#async)

    View Slide

  48. Fiber
    Fiber in ReactPHP
    (https://github.com/reactphp/async/blob/4.x/src/functions.php)

    View Slide

  49. Fiber
    Fiber in ReactPHP
    (https://github.com/reactphp/async/blob/4.x/src/functions.php)

    View Slide

  50. Fiber
    Fiber in Amp
    (https://github.com/amphp/http-client/blob/v5/examples/concurrency/1-concurrent-fetch.php)

    View Slide

  51. Fiber
    Fiber in Amp
    (https://github.com/amphp/amp/blob/v3/src/functions.php)

    View Slide

  52. Fiber
    Fiber in Amp
    (https://github.com/revoltphp/event-loop/blob/main/src/EventLoop/FiberLocal.php)

    View Slide

  53. Fiber
    Both ReactPHP and amp(3.0 beta) support Fiber now
    A comprehensive coroutine rather than semi-coroutine
    Eliminates yield statement for coroutines
    Fiber doesn't turn your code into non-blocking magically, traditional

    blocking code has to be rewritten for asynchronous I/O
    Help not too much for most of developers
    Fiber provides only bare minimum required to allow user code to

    implement full-stack coroutines in PHP
    Fiber doesn't support Preemptive Scheduling yet

    View Slide

  54. Questions
    What's the difference between Asynchronous and Coroutine?
    What's the difference between Generator and Fiber?
    How to turn Blocking I/O stream turning into Non-Blocking?
    What is Event Loop? Is it required for Asynchronous?
    What's the benefits of Coroutine?
    Is Asynchronous a must for Coroutine?
    How to make built-in Blocking I/O functions Asynchronous?
    Can Asynchronous I/O be integrated with traditional Blocking I/O

    environment? (e.g. PHP-FPM)

    View Slide

  55. Coroutine in Swoole
    Basic Usage
    ?

    View Slide

  56. Coroutine in Swoole
    Basic Usage
    start coro 1
    start to resume 1 @1
    resume coro 1 @1
    start to resume 1 @2
    resume coro 1 @2
    main

    View Slide

  57. Coroutine in Swoole
    Coroutine for Blocking I/O
    ?

    View Slide

  58. Coroutine in Swoole
    Coroutine for Blocking I/O
    coroutine start
    114.45.154.86
    coroutine end
    main

    View Slide

  59. Coroutine in Swoole
    Coroutine for Blocking I/O
    ?

    View Slide

  60. Coroutine in Swoole
    Coroutine for Blocking I/O
    coroutine start
    main
    xxx.xxx.xxx.xxx
    coroutine end

    View Slide

  61. Coroutine in Swoole
    Preemptive Scheduling
    ?

    View Slide

  62. Coroutine in Swoole
    Preemptive Scheduling

    View Slide

  63. Coroutine in Swoole
    Preemptive Scheduling
    ?

    View Slide

  64. Coroutine in Swoole
    Fatal error: Uncaught Exception:
    12.5ms end in xxx
    Stack trace:
    #0 {main}
    thrown in xxx
    Preemptive Scheduling

    View Slide

  65. Coroutine in Swoole
    Channel
    ?

    View Slide

  66. Coroutine in Swoole
    Channel
    [coroutine 3]
    int(0)
    [coroutine 2] - 0
    [coroutine 3]
    int(1)
    [coroutine 2] - 1
    [coroutine 3]
    ......

    View Slide

  67. Coroutine in Swoole
    Swoole implements its full coroutine features
    Built-in Blocking I/O functions can be replaced to Non-Blocking I/O

    automatically if hook flags are set
    Swoole supports Preemptive Scheduling for CPU-bound tasks
    Swoole Provides CSP Model for Coroutine Communications like in

    GoLang
    Yields and resumes take place behind the scenes for I/O functions

    switching

    View Slide

  68. Q&A

    View Slide