├── LICENSE ├── README.md └── axync.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mohammed Al Ashaal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # axync 2 | a smart cooperative multitasking kernel for php7 (only) . 3 | 4 | # show me the code ! 5 | 6 | ### Example 1 (simple) 7 | ```php 8 | require "axync.php"; 9 | 10 | // our workers builder 11 | $build = function($seq){ 12 | // this will be the generated coroutine 13 | // yes, it MUST yield ! 14 | return (function() use($seq) { 15 | for ( $i = 0; $i < 10; $i ++ ) { 16 | printf("Worker (%d): i'm in the step no. %d \n", $seq, $i); 17 | yield; 18 | } 19 | }); 20 | }; 21 | 22 | // create new manager 23 | (new Axync( 24 | $build(1), 25 | $build(2), 26 | $build(3) 27 | ))->exec(); 28 | 29 | // save your file as ~/tst1.php 30 | // open your terminal and `php ~/tst1.php` and see the result . 31 | ``` 32 | 33 | ### Example 2 (advanced) 34 | ```php 35 | require "axync.php"; 36 | 37 | // our workers builder 38 | $build = function($seq){ 39 | // this will be the generated coroutine 40 | // yes, it MUST yield ! 41 | return (function() use($seq) { 42 | for ( $i = 0; $i < 10; $i ++ ) { 43 | printf("Worker (%d): i'm in the step no. %d \n", $seq, $i); 44 | yield; 45 | } 46 | }); 47 | }; 48 | 49 | // create new manager 50 | // and convert to to a new Generator !! 51 | $manager1 = (new Axync( 52 | $build(1), 53 | $build(2), 54 | $build(3) 55 | ))->toGenerator(); 56 | 57 | // create a new manager that handles new generators 58 | (new Axync( 59 | $build(10), 60 | $build(20), 61 | $build(30), 62 | $manager1 // yes, axync support nested axync of axync too ;) 63 | ))->exec(); 64 | 65 | // save your file as ~/tst2.php 66 | // open your terminal and `php ~/tst2.php` and see the result . 67 | ``` 68 | -------------------------------------------------------------------------------- /axync.php: -------------------------------------------------------------------------------- 1 | . 11 | * - again just for fun . 12 | * 13 | * @version 1.0 14 | * @license MIT License 15 | * @author Mohammed Al Ashaal 16 | */ 17 | Class Axync { 18 | /** 19 | * array of registered coroutines 20 | * @var array $coroutines 21 | */ 22 | protected $coroutines = []; 23 | 24 | /** 25 | * Constructor 26 | * 27 | * @param Callable ... $params 28 | * @return $this 29 | */ 30 | public function __construct(Callable ... $params) { 31 | $this->register(...$params); 32 | } 33 | 34 | /** 35 | * register Generatable callbacks (callbacks that return generators) 36 | * 37 | * @param Callable ... $params 38 | * @return $this 39 | */ 40 | public function register(Callable ... $params) { 41 | foreach ( $params as $i => $obj ) { 42 | $this->coroutines[] = $obj; 43 | } 44 | return $this; 45 | } 46 | 47 | /** 48 | * execute each registered coroutine once . 49 | * 50 | * @return $this 51 | */ 52 | protected function tick() { 53 | foreach ( $this->coroutines as $i => $co ) { 54 | if ( is_callable($co) ) { 55 | $co = $this->coroutines[$i] = $co(); 56 | if ( ! $co instanceof Generator ) { 57 | throw new InvalidArgumentException(sprintf("The axync worker(%s) not valid", $i)); 58 | } 59 | $co->rewind(); 60 | } else if ( ! $co->valid() ) { 61 | unset($this->coroutines[$i]); 62 | } else { 63 | $co->next(); 64 | } 65 | } 66 | } 67 | 68 | /** 69 | * create a generator based tick. 70 | * 71 | * @return Generator 72 | */ 73 | protected function tickYield() { 74 | foreach ( $this->coroutines as $i => $co ) { 75 | if ( is_callable($co) ) { 76 | $co = $this->coroutines[$i] = $co(); 77 | if ( ! $co instanceof Generator ) { 78 | throw new InvalidArgumentException(sprintf("The axync worker(%s) not valid", $i)); 79 | } 80 | $co->rewind(); 81 | } else if ( ! $co->valid() ) { 82 | unset($this->coroutines[$i]); 83 | } else { 84 | $co->next(); 85 | } 86 | yield; 87 | } 88 | } 89 | 90 | /** 91 | * execute each registered coroutine till the end (blocking operation) . 92 | * 93 | * @return $this 94 | */ 95 | public function exec() { 96 | while ( sizeof($this->coroutines) > 0 ) { 97 | $this->tick(); 98 | } 99 | return $this; 100 | } 101 | 102 | /** 103 | * create a generator that will execute each registered coroutine (non-blocking operation) . 104 | * 105 | * @return Generator 106 | */ 107 | public function toGenerator() { 108 | return function(){ 109 | while ( sizeof($this->coroutines) > 0 ) { 110 | yield from $this->tickYield(); 111 | } 112 | }; 113 | } 114 | } 115 | --------------------------------------------------------------------------------