Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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)

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Asynchronous I/O in PHP ReactPHP

Slide 17

Slide 17 text

Asynchronous I/O in PHP ReactPHP

Slide 18

Slide 18 text

Asynchronous I/O in PHP Amp

Slide 19

Slide 19 text

Asynchronous I/O in PHP Amp

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Asynchronous I/O in PHP Event Loop in ReactPHP

Slide 23

Slide 23 text

Asynchronous I/O in PHP Event Loop in ReactPHP

Slide 24

Slide 24 text

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)

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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)

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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)

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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)

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Fiber Fiber Class

Slide 39

Slide 39 text

Fiber Basic Usage ?

Slide 40

Slide 40 text

Fiber Basic Usage fiber start fiber suspend fiber continue done

Slide 41

Slide 41 text

Fiber Basic Usage ?

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

Fiber Basic Usage ?

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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)

Slide 55

Slide 55 text

Coroutine in Swoole Basic Usage ?

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

Coroutine in Swoole Coroutine for Blocking I/O ?

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

Coroutine in Swoole Coroutine for Blocking I/O ?

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

Coroutine in Swoole Preemptive Scheduling ?

Slide 62

Slide 62 text

Coroutine in Swoole Preemptive Scheduling

Slide 63

Slide 63 text

Coroutine in Swoole Preemptive Scheduling ?

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

Coroutine in Swoole Channel ?

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

Q&A