PHP рдореЗрдВ Coroutines рдФрд░ рдЧреИрд░-рдЕрд╡рд░реБрджреНрдз рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛

PHP 5.5 рдореЗрдВ рд╕рдмрд╕реЗ рдмрдбрд╝реА рдирд╡рд╛рдЪрд╛рд░реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдЬрдирд░реЗрдЯрд░ рдФрд░ рдХреЛрд░рдЖрдЙрдЯ (рдХреЛрд░рд╛рдЙрдЯрд╛рдЗрди) рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рд╣реЛрдЧрд╛ред рдЬрдирд░реЗрдЯрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рджрд╕реНрддрд╛рд╡реЗрдЬ рдореЗрдВ рдФрд░ рдХрдИ рдЕрдиреНрдп рдкрджреЛрдВ рдкрд░ рдкрд░реНрдпрд╛рдкреНрдд рд░реВрдк рд╕реЗ рдХрд╡рд░ рдХрд┐рдП рдЧрдП рд╣реИрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдпрд╛ рдпрд╣ )ред Coroutines рдХреЛ рдмрд╣реБрдд рдХрдо рдзреНрдпрд╛рди рдорд┐рд▓рд╛ред рдпрд╣ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд╣реИ, рд▓реЗрдХрд┐рди рдЯреВрд▓ рдХреЛ рд╕рдордЭрдиреЗ рдФрд░ рд╕рдордЭрд╛рдиреЗ рдореЗрдВ рднреА рдЕрдзрд┐рдХ рдХрдард┐рди рд╣реИред

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдХреЛрд░рдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдХрд╛рд░реНрдп рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдП, рддрд╛рдХрд┐ рдЖрдк рд╕рдордЭ рд╕рдХреЗрдВ рдХрд┐ рдЖрдк рдЙрдирдХреЗ рд╕рд╛рде рдХреНрдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЪрд▓рд┐рдП рдХреБрдЫ рдкрд░рд┐рдЪрдпрд╛рддреНрдордХ рд╢рдмреНрджреЛрдВ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЬрдирд░реЗрдЯрд░ рдФрд░ рдХреЛрд░рдЯрд╛рдЗрди рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рддреБрд░рдВрдд "рд╕рдВрдпреБрдХреНрдд рдорд▓реНрдЯреАрдЯрд╛рд╕реНрдХрд┐рдВрдЧ" рдЕрдиреБрднрд╛рдЧ рдкрд░ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред

рдЬрдирд░реЗрдЯрд░


рдЬрдирд░реЗрдЯрд░ рдХрд╛ рд╕рд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдРрд╕рд╛ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рди рдХреЗрд╡рд▓ рдПрдХ рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдореВрд▓реНрдпреЛрдВ рдХрд╛ рдПрдХ рдХреНрд░рдо рд╣реИ , рдЬрд╣рд╛рдВ рдкреНрд░рддреНрдпреЗрдХ рдорд╛рди рдХреЛ рдПрдХ рджреВрд╕рд░реЗ рд╕реЗ рдлреЗрдВрдХ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╛, рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдЬрдирд░реЗрдЯрд░ рдЖрдкрдХреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдХреЛрдб рдХреЗ рдмрд┐рдирд╛, рдПрдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг xrange() рдлрд╝рдВрдХреНрд╢рди рд╣реИ:
 function xrange($start, $end, $step = 1) { for ($i = $start; $i <= $end; $i += $step) { yield $i; } } foreach (xrange(1, 1000000) as $num) { echo $num, "\n"; } 


рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд PHP, range() ред рдЕрдВрддрд░ рдХреЗрд╡рд▓ рдЗрддрдирд╛ рд╣реИ рдХрд┐ рд╡рд╣ range() рдЖрдкрдХреЛ рдПрдХ рдорд┐рд▓рд┐рдпрди рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рдПрдХ рд╕рд░рдгреА xrange() , рдФрд░ xrange() рдПрдХ xrange() рд▓реМрдЯрд╛рдПрдЧрд╛ рдЬреЛ рдЙрди рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рджреВрд░ рдлреЗрдВрдХ рджреЗрдЧрд╛, рд▓реЗрдХрд┐рди рдЙрди рд╕рднреА рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд░рдгреА рдХрднреА рдирд╣реАрдВ рдмрдирд╛рдПрдЧрд╛ред

рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд▓рд╛рдн рд╕реНрдкрд╖реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕ рддрд░рд╣ рдЖрдк рдЙрди рд╕рднреА рдХреЛ рдореЗрдореЛрд░реА рдореЗрдВ рд▓реЛрдб рдХрд┐рдП рдмрд┐рдирд╛ рдмрд╣реБрдд рдмрдбрд╝реЗ рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рддреБрдо рднреА рдЕрдВрддрд╣реАрди рдбреЗрдЯрд╛ рдзрд╛рд░рд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдпрд╣ рд╕рдм рдЬреЗрдирд░реЗрдЯрд░ рдХреЗ рдмрд┐рдирд╛ рднреА рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ Iterator рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ рд╡рд░реНрдЧ рдмрдирд╛рдХрд░ред рдЬрдирд░реЗрдЯрд░ рдХреЗрд╡рд▓ рдЗрд╕реЗ (рдмрд╣реБрдд) рд╕рд░рд▓ рдЕрднреНрдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рдЖрдкрдХреЛ рдкреНрд░рддреНрдпреЗрдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рд▓рд┐рдП рдкрд╛рдВрдЪ рдЕрд▓рдЧ-рдЕрд▓рдЧ рддрд░реАрдХреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред

рдЬрдирд░реЗрдЯрд░реЛрдВ рдореЗрдВ рд░реБрдХрд╛рд╡рдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп


рдЬрдирд░реЗрдЯрд░ рд╕реЗ рдХреЛрд░рдЯрд╛рдЗрди рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдпрд╣ рд╕рдордЭрдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ рд╡реЗ рдЕрдВрджрд░ рд╕реЗ рдХреИрд╕реЗ рдмрдирд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ: рдЬрдирд░реЗрдЯрд░ рдЕрд╡рд░реЛрдзрдХ рдХрд╛рд░реНрдп рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ yield рдХреАрд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рд░реБрдХрд╛рд╡рдЯреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ xrange(1, 1000000) , рдЬрдм рдЖрдк xrange(1, 1000000) , рддреЛ xrange рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╢рд░реАрд░ рд╕реЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, PHP рдмрд╕ рдПрдХ Generator рдСрдмреНрдЬреЗрдХреНрдЯ рд▓реМрдЯрд╛рдПрдЧрд╛ рдЬреЛ Iterator рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ:
 <?php $range = xrange(1, 1000000); var_dump($range); // object(Generator)#1 var_dump($range instanceof Iterator); // bool(true) 


рдХреЛрдб рдХреЗрд╡рд▓ рддрднреА рдЪрд▓реЗрдЧрд╛ рдЬрдм рдЖрдк рдХреБрдЫ рдкреБрдирд░рд╛рд╡реГрддреНрдд рддрд░реАрдХреЗ рдЪрд▓рд╛рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЖрдк $range->rewind() рддреЛ рдкрд╣рд▓реА yield рд╕реЗ рдкрд╣рд▓реЗ xrange() рдлрд╝рдВрдХреНрд╢рди $range->rewind() рдХреЛрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ $i = $start рдХреЛ рдкрд╣рд▓реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдлрд┐рд░ yield $i рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рд╣рдо рдЬреЛ рдХреБрдЫ рднреА yield рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рд╡рд╣ $range->current() рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ $range->next() рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдпрд╣ рдЬрдирд░реЗрдЯрд░ рдХреЛ рдЕрдЧрд▓реА yield рддрдХ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░рддрд╛ yield ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, next() рдФрд░ current() рд▓рд┐рдП рд▓рдЧрд╛рддрд╛рд░ рдХреЙрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рдЬрдирд░реЗрдЯрд░ рд╕реЗ рд╕рднреА рдорд╛рди рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рддрдХ рдХрд┐ рдпрд╣ рдЙрд╕ рдмрд┐рдВрджреБ рддрдХ рдирд╣реАрдВ рдкрд╣реБрдВрдЪрддрд╛ рдЬрд╣рд╛рдВ рдХреЛрдб рдмрд╕ рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИред xrange() рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ xrange() рдпрд╣ рддрдм рд╣реЛрдЧрд╛ рдЬрдм $i $end рддрдХ рдкрд╣реБрдВрдЪ $end ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдирд┐рд╖реНрдкрд╛рджрди рдХрд╛ рдзрд╛рдЧрд╛ рдЕрдзрд┐рдХ рдХреЛрдб рдЫреЛрдбрд╝рдиреЗ рдХреЗ рдмрд┐рдирд╛ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдВрдд рддрдХ рдкрд╣реБрдВрдЪрддрд╛ рд╣реИред рдРрд╕рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, valid() false рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдЪрд▓рдирд╛ рдмрдВрдж рд╣реЛ рдЬрд╛рдПрдЧрд╛ред

coroutine


рдЙрдкрд░реЛрдХреНрдд рдХрд╛рд░реНрдпрд╢реАрд▓рддрд╛ рдореЗрдВ рдореБрдЦреНрдп рдЪреАрдЬрд╝ рдЬреЛ рдХреЛрд░рдЯрд╛рдЗрди рдЬреЛрдбрд╝рддреА рд╣реИ, рд╡рд╣ рдЬрдирд░реЗрдЯрд░ рдХреЛ рдорд╛рди рднреЗрдЬрдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реИред рдпрд╣ рдЬрдирд░реЗрдЯрд░ рдХреЗ рд╕рд╛рдорд╛рдиреНрдп рдПрдХрд╛рд▓рд╛рдк рдХреЛ рдкреВрд░реНрдг рд╕рдВрд╡рд╛рдж рдмрдирд╛рддрд╛ рд╣реИ, рдЬрд╣рд╛рдВ рдХреЙрд▓рд░ рдЬрдирд░реЗрдЯрд░ рдХреЛ рднреА рдХреБрдЫ рдмрддрд╛ рд╕рдХрддрд╛ рд╣реИред

next() рдмрдЬрд╛рдп рдХреЙрд▓ send() рджреНрд╡рд╛рд░рд╛ рдорд╛рдиреЛрдВ рдХреЛ рдХреЛрд░рдЯрд╛рдЗрди рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ:
 function logger($fileName) { $fileHandle = fopen($fileName, 'a'); while (true) { fwrite($fileHandle, yield . "\n"); } } $logger = logger(__DIR__ . '/log'); $logger->send('Foo'); $logger->send('Bar'); 


рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣рд╛рдВ yield рдПрдХ рдмрдпрд╛рди (рдЬреИрд╕реЗ return рдпрд╛ echo ) рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рд░реВрдк рдореЗрдВ, рдпрд╣ рдПрдХ рдореВрд▓реНрдп рд╣реИред рдпрд╣ рд╡рд╣ send() рдЬреЛ рднреЗрдЬреЗ send() рдорд╛рдзреНрдпрдо рд╕реЗ рднреЗрдЬрд╛ рдЧрдпрд╛ рдерд╛ред рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, yield "Foo" рдФрд░ рдлрд┐рд░ "Bar" рд╡рд╛рдкрд╕ рдЖ yield ред

рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдпрд╣ рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдХрд┐ yield рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдХреИрд╕реЗ рдХрд╛рд░реНрдп рдХрд░ рд╕рдХрддреА рд╣реИред рд▓реЗрдХрд┐рди рдЖрдк рджреЛрдиреЛрдВ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЛ рднреА рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдЖрдк рдорд╛рди рднреЗрдЬ рдФрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЗрд╕рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ:
 function gen() { $ret = (yield 'yield1'); var_dump($ret); $ret = (yield 'yield2'); var_dump($ret); } $gen = gen(); var_dump($gen->current()); // string(6) "yield1" var_dump($gen->send('ret1')); // string(4) "ret1" (the first var_dump in gen) // string(6) "yield2" (the var_dump of the ->send() return value) var_dump($gen->send('ret2')); // string(4) "ret2" (again from within gen) // NULL (the return value of ->send()) 


рд╕рдЯреАрдХ рдЖрдЙрдЯрдкреБрдЯ рдСрд░реНрдбрд░ рдкрд╣рд▓реА рдирдЬрд╝рд░ рдореЗрдВ рд╕рдордЭрдиреЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рдореБрд╢реНрдХрд┐рд▓ рд▓рдЧ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдХреЛрдб рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрдврд╝реЗрдВ рдФрд░ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдЦреБрдж рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВ рдХрд┐ рдЙрд╕ рдХреНрд░рдо рдореЗрдВ рд╕рдм рдХреБрдЫ рдХреНрдпреЛрдВ рд╣реЛрддрд╛ рд╣реИред рдпрд╣рд╛рдВ рджреЛ рдЪреАрдЬреЗрдВ рд╣реИрдВ рдЬреЛ рдореИрдВ рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ: рдкрд╣рд▓рд╛, yield рдЖрд╕рдкрд╛рд╕ рдХреЛрд╖реНрдардХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреЛрдИ рджреБрд░реНрдШрдЯрдирд╛ рдирд╣реАрдВ рд╣реИред рд╣рдореЗрдВ рддрдХрдиреАрдХреА рдХрд╛рд░рдгреЛрдВ рд╕реЗ рдЗрди рдХреЛрд╖реНрдардХреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдореИрдВрдиреЗ рдкреНрд░рддреНрдпрдХреНрд╖ рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдореЗрдВ рдПрдХ рдЕрдкрд╡рд╛рдж рдлреЗрдВрдХ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рд╕реЛрдЪрд╛ рдерд╛)ред рджреВрд╕рд░реЗ, рдЖрдкрдиреЗ рджреЗрдЦрд╛ рд╣реЛрдЧрд╛ рдХрд┐ current() рдХрд╛ рдЙрдкрдпреЛрдЧ rewind() рдмрд┐рдирд╛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред rewind() , рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рддрдм рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд░реВрдк рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рд╕рд╣рдпреЛрдЧреА рдорд▓реНрдЯреАрдЯрд╛рд╕реНрдХрд┐рдВрдЧ


рдпрджрд┐ рдЖрдк рдЙрджрд╛рд╣рд░рдг logger() рдлрд╝рдВрдХреНрд╢рди рдкрдврд╝рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдиреЗ рд╕реЛрдЪрд╛, тАЬрдореИрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХреЛрд░рдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдХрд░реВрдВрдЧрд╛? рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╡рд░реНрдЧ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдмрдирд╛рдпрд╛ рдЧрдпрд╛? тАЭ, рддреЛ рдЖрдк рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╣реА рдереЗред рдпрд╣ рдЙрджрд╛рд╣рд░рдг рдХреЗрд╡рд▓ рдпрд╣ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреЛрд░рдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рдХрд╛рд░рдг рдирд╣реАрдВ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ рдКрдкрд░ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдкрд░рд┐рдЪрдп рдореЗрдВ, рдХреЛрд░рдЯрд╛рдЗрди рдПрдХ рдмрд╣реБрдд рд╣реА рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдЪреАрдЬ рд╣реИ, рд▓реЗрдХрд┐рди рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдмрд╣реБрдд рд╣реА рджреБрд░реНрд▓рдн рдФрд░ рдЕрдХреНрд╕рд░ рдмрд╣реБрдд рдЬрдЯрд┐рд▓ рд╣реЛрддрд╛ рд╣реИ, рдЬреЛ рд╕рд░рд▓ рдФрд░ рджреВрд░-рджрд░рд╛рдЬ рдХреЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдЖрдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдХрд╛рдлреА рдХрдард┐рди рдмрдирд╛ рджреЗрддрд╛ рд╣реИред

рдореИрдВрдиреЗ рдЖрдкрдХреЛ рдХреЛрд░рдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рд╣рдпреЛрдЧреА рдорд▓реНрдЯреАрдЯрд╛рд╕реНрдХрд┐рдВрдЧ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рджрд┐рдЦрд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред рд▓рдмреНрдмреЛрд▓реБрдЖрдм рдпрд╣ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрдИ рдХрд╛рд░реНрдп рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдЪрд▓рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдПрдХ рдкреНрд░реЛрд╕реЗрд╕рд░ (рд▓рдЧрднрдЧ рд▓реЗрдиред рдЧреЛрд▓рд╛рдХрд╛рд░ рдФрд░ рд╡реИрдХреНрдпреВрдо рдореЗрдВ) рдПрдХ рд╕рдордп рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рдХрд╛рд░реНрдп рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЛ рд╡рд┐рднрд┐рдиреНрди рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмреАрдЪ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ "рдереЛрдбрд╝рд╛ рдХрд╛рдо" рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред

"рдЬреЙрдЗрдВрдЯ" рдпрд╣ рдорд▓реНрдЯреАрдЯрд╛рд╕реНрдХрд┐рдВрдЧ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдореЗрдВ рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрди рдХрд╛ рдирд┐рдпрдВрддреНрд░рдг рд╕реНрд╡реЗрдЪреНрдЫрд╛ рд╕реЗ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИ рддрд╛рдХрд┐ рд╡рд╣ рдПрдХ рдФрд░ рдХрд╛рд░реНрдп рд╢реБрд░реВ рдХрд░ рд╕рдХреЗред рдкреНрд░реАрдореЗрдкреНрдЯрд┐рд╡ рдорд▓реНрдЯреАрдЯрд╛рд╕реНрдХрд┐рдВрдЧ рднреА рд╣реИ, рдЬрд╣рд╛рдБ рд╢реЗрдбреНрдпреВрд▓рд░ рд╕реНрд╡рдпрдВ рдХрд╛рд░реНрдп рдХреЛ рдмрд╛рдзрд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред рд╕рд╣рдпреЛрдЧрд╛рддреНрдордХ рдорд▓реНрдЯреАрдЯрд╛рд╕реНрдХрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд┐рдВрдбреЛрдЬ рдХреЗ рдкреБрд░рд╛рдиреЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ (Win95 рд╕реЗ рдкрд╣рд▓реЗ) рдФрд░ рдореИрдХ рдУрдПрд╕ рдореЗрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдлрд┐рд░ рдЙрдиреНрд╣реЛрдВрдиреЗ рдкреНрд░реАрдореЗрдкреНрдЯрд┐рд╡ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░ рджрд┐рдпрд╛ред рдХрд╛рд░рдг рд╕реНрдкрд╖реНрдЯ рд╣реИ - рдпрджрд┐ рдЖрдк рдирд┐рдпрдВрддреНрд░рдг рдкреНрд░рд╡рд╛рд╣ рдХреЛ рд╕реНрд╡реЗрдЪреНрдЫрд╛ рд╕реЗ рдЫреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рд╕реА рднреА рдХрд╛рд░реНрдпрдХреНрд░рдо рдкрд░ рднрд░реЛрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдХреЛрдИ рднреА рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗрд╡рд▓ рд╕рдВрдкреВрд░реНрдг рд╕реАрдкреАрдпреВ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рдЕрдм рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреЛрд░рдЯрд╛рдЗрди рдФрд░ рдЯрд╛рд╕реНрдХ рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЗ рдмреАрдЪ рд╕рдВрдмрдВрдз рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдП: yield рдЖрдкрдХреЛ рд╢реЗрдбреНрдпреВрд▓рд░ рдирд┐рдпрдВрддреНрд░рдг рдкреНрд░рд╡рд╛рд╣ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдХреЛ рд╕реНрд╡рдпрдВ рдмрд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдФрд░ рдпрд╣ рдПрдХ рдФрд░ рдХрд╛рд░реНрдп рд╢реБрд░реВ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕рдВрдкреНрд░реЗрд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП yield рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдХрд╛рд░реНрдп рдЬрдирд░реЗрдЯрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЖрд╕рдкрд╛рд╕ рдПрдХ рдкрддрд▓рд╛ рдЖрд╡рд░рдг рд╣реЛрдЧрд╛:
 class Task { protected $taskId; protected $coroutine; protected $sendValue = null; protected $beforeFirstYield = true; public function __construct($taskId, Generator $coroutine) { $this->taskId = $taskId; $this->coroutine = $coroutine; } public function getTaskId() { return $this->taskId; } public function setSendValue($sendValue) { $this->sendValue = $sendValue; } public function run() { if ($this->beforeFirstYield) { $this->beforeFirstYield = false; return $this->coroutine->current(); } else { $retval = $this->coroutine->send($this->sendValue); $this->sendValue = null; return $retval; } } public function isFinished() { return !$this->coroutine->valid(); } } 


рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрдп рдХрд╛ рдЕрдкрдирд╛ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ ( taskId ) рд╣реЛрдЧрд╛ред setSendValue() рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рдЕрдЧрд▓реЗ рд░рди рдкрд░ рдХрд╛рд░реНрдп рдХреЛ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдореВрд▓реНрдп рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдЖрдкрдХреЛ рдмрд╛рдж рдореЗрдВ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ)ред run() рд╡рд┐рдзрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рд┐рд░реНрдл рдХреЙрд░рдЯрд╛рдЗрдиреНрд╕ send() рд╡рд┐рдзрд┐ рдХрд╣рддреА рд╣реИред
рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣рдореЗрдВ рдкрд╣рд▓реЗ beforeFirstYield рдлрд╝реНрд▓реИрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ, рдирд┐рдореНрди рдХреЛрдб рдХреЛ рджреЗрдЦреЗрдВ:
 function gen() { yield 'foo'; yield 'bar'; } $gen = gen(); var_dump($gen->send('something')); //   send(),   yield    rewind() //       : $gen->rewind(); var_dump($gen->send('something')); // rewind()    yield (   ), send() //    yield ( var_dump-  ). //       


beforeFirstYield рд╕рд╛рде beforeFirstYield рд╣рдореЗрдВ рдкрддрд╛ рдЪрд▓ рдЬрд╛рдПрдЧрд╛ рдХрд┐ рдХреНрдпрд╛ рдкрд╣рд▓реА рдЙрдкрдЬ рдкрд╣рд▓реЗ рд╣реА рд╡рд╛рдкрд╕ рдЖ рдЧрдИ рд╣реИред

рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЛ рдЕрдм рд╕рднреА рдХрд╛рд░реНрдпреЛрдВ рд╕реЗ рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рдЪрд▓рдирд╛ рд╣реЛрдЧрд╛:
 class Scheduler { protected $maxTaskId = 0; protected $taskMap = []; // taskId => task protected $taskQueue; public function __construct() { $this->taskQueue = new SplQueue(); } public function newTask(Generator $coroutine) { $tid = ++$this->maxTaskId; $task = new Task($tid, $coroutine); $this->taskMap[$tid] = $task; $this->schedule($task); return $tid; } public function schedule(Task $task) { $this->taskQueue->enqueue($task); } public function run() { while (!$this->taskQueue->isEmpty()) { $task = $this->taskQueue->dequeue(); $task->run(); if ($task->isFinished()) { unset($this->taskMap[$task->getTaskId()]); } else { $this->schedule($task); } } } } 


newTask() рд╡рд┐рдзрд┐ рдПрдХ рдирдпрд╛ рдХрд╛рд░реНрдп рдмрдирд╛рддреА рд╣реИ рдФрд░ рдЗрд╕реЗ taskMap рдореЗрдВ taskMap ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡рд╣ рдЗрд╕реЗ taskQueue рдЬреЛрдбрд╝рддрд╛ рд╣реИред run() рд╡рд┐рдзрд┐ рддрдм рдЗрд╕ рдХрддрд╛рд░ рд╕реЗ рдЧреБрдЬрд░рддреА рд╣реИ рдФрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╢реБрд░реВ рдХрд░рддреА рд╣реИред рдпрджрд┐ рдХрд╛рд░реНрдп рдкреВрд░рд╛ рд╣реЛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдЗрд╕реЗ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЕрдиреНрдпрдерд╛ рдЗрд╕реЗ рдХрддрд╛рд░ рдХреЗ рдЕрдВрдд рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЖрдЗрдП рдПрдХ рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рджреЛ рд╕рд░рд▓ (рдФрд░ рдЕрд░реНрдерд╣реАрди) рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдЖрдЬрд╝рдорд╛рдПрдБ:
 function task1() { for ($i = 1; $i <= 10; ++$i) { echo "This is task 1 iteration $i.\n"; yield; } } function task2() { for ($i = 1; $i <= 5; ++$i) { echo "This is task 2 iteration $i.\n"; yield; } } $scheduler = new Scheduler; $scheduler->newTask(task1()); $scheduler->newTask(task2()); $scheduler->run(); 


рджреЛрдиреЛрдВ рдХрд╛рд░реНрдп рдХреЗрд╡рд▓ рдПрдХ рд╕рдВрджреЗрд╢ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЛ рд╡рд╛рдкрд╕ рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЛ рджреЗрддреЗ рд╣реИрдВред рдпрд╣рд╛рдБ рдЖрдЙрдЯрдкреБрдЯ рдХреНрдпрд╛ рд╣реЛрдЧрд╛:
  рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 1 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 2 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 1 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 2 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 2 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 2 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 3 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 2 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 3 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 4 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 2 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 4 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 5 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 2 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 5 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 6 тАЛтАЛрд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 7 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 8 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 9 рд╣реИред
 рдпрд╣ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 10 рд╣реИред 


рд╢реЗрдбреНрдпреВрд▓рд░ рдЗрдВрдЯрд░реИрдХреНрд╢рди


рдЗрд╕рд▓рд┐рдП, рд╣рдорд╛рд░рд╛ рд╢реЗрдбреНрдпреВрд▓рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╣рдо рдПрдЬреЗрдВрдбреЗ рдкрд░ рдЕрдЧрд▓реЗ рдЖрдЗрдЯрдо рдкрд░ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ: рдХрд╛рд░реНрдпреЛрдВ рдФрд░ рдЕрдиреБрд╕реВрдЪрдХ рдХреЗ рдмреАрдЪ рдмрд╛рддрдЪреАрддред рд╣рдо рдЙрд╕реА рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ рдЬреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдВ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рд╛рде рд╕рдВрдЪрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИрдВ: рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ (syscall, siskol)ред рд╣рдореЗрдВ syskols рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рд╕реНрд╡рдпрдВ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рд╡рд┐рд╢реЗрд╖рд╛рдзрд┐рдХрд╛рд░реЛрдВ рдХреЗ рдПрдХ рдЕрд▓рдЧ рд╕реНрддрд░ рдкрд░ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдХреБрдЫ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдиреНрд╣реЗрдВ рдЕрдзрд┐рдХ рд╡рд┐рд╢реЗрд╖рд╛рдзрд┐рдХрд╛рд░реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЕрдиреНрдп рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдорд╛рд░рдирд╛), рдХрд░реНрдиреЗрд▓ рдХреЛ рдирд┐рдпрдВрддреНрд░рдг рджреЗрдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рддрд╛рдХрд┐ рдпрд╣ рдЙрди рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд░ рд╕рдХреЗред рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ, рдпрд╣ рд░реБрдХрд╛рд╡рдЯ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рд╣рдорд╛рд░рд╛ рд╢реЗрдбреНрдпреВрд▓рд░ рдЗрд╕ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХрд╛ рдкрд╛рд▓рди рдХрд░реЗрдЧрд╛: рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЛ рдХрд╛рд░реНрдп рдХреЗ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп (рдЬреЛ рдЗрд╕рдХреЗ рд╕рд╛рде рдХреБрдЫ рднреА рдХрд░ рд╕рдХрддрд╛ рд╣реИ), рд╣рдо yield рдорд╛рдзреНрдпрдо рд╕реЗ рдкрд╛рд░рд┐рдд рдкрд╛рд╕рд╡рд░реНрдб рдХреА рдорджрдж рд╕реЗ рдмрд╛рддрдЪреАрдд рдХрд░реЗрдВрдЧреЗред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, yield рдПрдХ рдмреНрд░реЗрдХрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдФрд░ рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рд╕реВрдЪрдирд╛ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░рдиреЗ (рдФрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ) рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░реЗрдЧрд╛ред

рд╕рд┐рд╕реНрдХреЛрд▓ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдХреЙрд▓ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдкрд░ рдПрдХ рдЫреЛрдЯреЗ рдЖрд╡рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛:
 class SystemCall { protected $callback; public function __construct(callable $callback) { $this->callback = $callback; } public function __invoke(Task $task, Scheduler $scheduler) { $callback = $this->callback; // Can't call it directly in PHP :/ return $callback($task, $scheduler); } } 


рдпрд╣ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп callable рдпреЛрдЧреНрдп рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░реЗрдЧрд╛, рд▓реЗрдХрд┐рди рдХрд╛рд░реНрдп рдФрд░ рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рддрд░реНрдХреЛрдВ рдореЗрдВ рд▓реЗ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рд╢реЗрдбреНрдпреВрд▓рд░ рдХреА run() рд╡рд┐рдзрд┐ рдХреЛ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛:
 public function run() { while (!$this->taskQueue->isEmpty()) { $task = $this->taskQueue->dequeue(); $retval = $task->run(); if ($retval instanceof SystemCall) { $retval($task, $this); continue; } if ($task->isFinished()) { unset($this->taskMap[$task->getTaskId()]); } else { $this->schedule($task); } } } 


рд╣рдорд╛рд░рд╛ рдкрд╣рд▓рд╛ syskol рдмрд╕ рдХрд╛рд░реНрдп рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЛ рд▓реМрдЯрд╛рдПрдЧрд╛:
 function getTaskId() { return new SystemCall(function(Task $task, Scheduler $scheduler) { $task->setSendValue($task->getTaskId()); $scheduler->schedule($task); }); } 


рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реЛрддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рди рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдХрд╛рд░реНрдп рдХреЛ рд╢реЗрдбреНрдпреВрд▓рд░ рдкрд░ рд╡рд╛рдкрд╕ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред Syskol рдХреЗ рд▓рд┐рдП, рдЕрдиреБрд╕реВрдЪрдХ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдХрддрд╛рд░ рдореЗрдВ рдХрд╛рд░реНрдп рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд╣рдореЗрдВ рдЗрд╕реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдЖрдкрдХреЛ рдкрддрд╛ рдЪрд▓ рдЬрд╛рдПрдЧрд╛ рдХрд┐ рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж рдХреНрдпреЛрдВ)ред
рдЗрд╕ рдирдП рд╕рд┐рд╕реНрдХреЛрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рд╣рдо рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
 function task($max) { $tid = (yield getTaskId()); // <-- here's the syscall! for ($i = 1; $i <= $max; ++$i) { echo "This is task $tid iteration $i.\n"; yield; } } $scheduler = new Scheduler; $scheduler->newTask(task(10)); $scheduler->newTask(task(5)); $scheduler->run(); 


рдпрд╣ рдХреЛрдб рд╣рдореЗрдВ рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рдорд╛рди рдЖрдЙрдЯрдкреБрдЯ рджреЗрдЧрд╛ред рдирдП рдФрд░ рдорд╛рд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЬреЛрдбрд╝реА siskols:
 function newTask(Generator $coroutine) { return new SystemCall( function(Task $task, Scheduler $scheduler) use ($coroutine) { $task->setSendValue($scheduler->newTask($coroutine)); $scheduler->schedule($task); } ); } function killTask($tid) { return new SystemCall( function(Task $task, Scheduler $scheduler) use ($tid) { $task->setSendValue($scheduler->killTask($tid)); $scheduler->schedule($task); } ); } 


killTask рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП killTask рд╣рдореЗрдВ рд╢реЗрдбреНрдпреВрд▓рд░ рдореЗрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
 public function killTask($tid) { if (!isset($this->taskMap[$tid])) { return false; } unset($this->taskMap[$tid]); //        , //      ,       foreach ($this->taskQueue as $i => $task) { if ($task->getTaskId() === $tid) { unset($this->taskQueue[$i]); break; } } return true; } 


рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЫреЛрдЯреА рд╕реНрдХреНрд░рд┐рдкреНрдЯ:
 function childTask() { $tid = (yield getTaskId()); while (true) { echo "Child task $tid still alive!\n"; yield; } } function task() { $tid = (yield getTaskId()); $childTid = (yield newTask(childTask())); for ($i = 1; $i <= 6; ++$i) { echo "Parent task $tid iteration $i.\n"; yield; if ($i == 3) yield killTask($childTid); } } $scheduler = new Scheduler; $scheduler->newTask(task()); $scheduler->run(); 


рдирд┐рд╖реНрдХрд░реНрд╖ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реЛрдЧрд╛:
  рдореВрд▓ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 1ред
 рдмрд╛рд▓ рдХрд╛рд░реНрдп 2 рдЕрднреА рднреА рдЬреАрд╡рд┐рдд рд╣реИ!
 рдореВрд▓ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 2ред
 рдмрд╛рд▓ рдХрд╛рд░реНрдп 2 рдЕрднреА рднреА рдЬреАрд╡рд┐рдд рд╣реИ!
 рдореВрд▓ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 3ред
 рдмрд╛рд▓ рдХрд╛рд░реНрдп 2 рдЕрднреА рднреА рдЬреАрд╡рд┐рдд рд╣реИ!
 рдореВрд▓ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 4ред
 рдореВрд▓ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 5ред
 рдореВрд▓ рдХрд╛рд░реНрдп 1 рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ 6ред 


рдмрд╛рд▓ рдХрд╛рд░реНрдп рддреАрди рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдпреЛрдВ рдХреЗ рдмрд╛рдж рдорд╛рд░рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдлрд┐рд░ "рдмрд╛рд▓ рдХрд╛рд░реНрдп рдЕрднреА рднреА рдЬреАрд╡рд┐рдд рд╣реИ!" рд╕рдВрджреЗрд╢ рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИред рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдорд╛рддрд╛-рдкрд┐рддрд╛ рдФрд░ рдмрдЪреНрдЪрд╛ рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдмрдЪреНрдЪреЗ рдХреЗ рдХрд╛рд░реНрдп рдХреЛ рддрдм рднреА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬрдм рдорд╛рддрд╛-рдкрд┐рддрд╛ рдкрд╣рд▓реЗ рд╣реА рдкреВрд░рд╛ рдХрд░ рдЪреБрдХреЗ рд╣реЛрдВред рдпрд╛ рдмреЗрдЯреА рдорд╛рддрд╛-рдкрд┐рддрд╛ рдХреЛ рднреА рдорд╛рд░ рд╕рдХрддреА рд╣реИред рд╣рдо рдорд╛рддрд╛-рдкрд┐рддрд╛ рдФрд░ рдмрдЪреНрдЪреЗ рдХреЗ рдмреАрдЪ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рд╕рдВрдмрдВрдз рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдирд╣реАрдВред

рдХреБрдЫ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреНрд░рдХрд╛рд░ рдХреА рдХреЙрд▓ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдЖрдк рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ wait (рдХрд╛рд░реНрдп рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ), exec (рдЬреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдЕрдм рдХрд┐рд╕ рдХрд╛рд░реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ) рдФрд░ fork (рдХрд╛рд░реНрдп рдХрд╛ рдХреНрд▓реЛрди рдмрдирд╛рдирд╛)ред рдХреНрд▓реЛрдирд┐рдВрдЧ рдПрдХ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рд╕реБрд╡рд┐рдзрд╛ рд╣реИ рдФрд░ рдЖрдк рдЗрд╕реЗ рдХреЛрд░рдЯрд╛рдЗрди рдХреЗ рд╕рд╛рде рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рдХреНрд▓реЛрдирд┐рдВрдЧ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВред

рдЧреИрд░-рдЕрд╡рд░реБрджреНрдз рдмрд╛рддрдЪреАрдд


рдПрдХ рд╡реЗрдм рд╕рд░реНрд╡рд░ - рд╣рдорд╛рд░реЗ рдЕрдиреБрд╕реВрдЪрдХ рдХрд╛ рдПрдХ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╕реНрдкрд╖реНрдЯ рд╣реИред рдирдП рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рд╕реЙрдХреЗрдЯ рдкрд░ рдПрдХ рдХрд╛рд░реНрдп рд╕реБрдирдирд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рд╣рд░ рдмрд╛рд░ рдПрдХ рдирдпрд╛ рдХрдиреЗрдХреНрд╢рди рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕ рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдХрд╛рд░реНрдп рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдХрдард┐рдирд╛рдИ рдЗрд╕ рддрдереНрдп рдореЗрдВ рдирд┐рд╣рд┐рдд рд╣реИ рдХрд┐ PHP рдореЗрдВ рдбреЗрдЯрд╛ рдкрдврд╝рдиреЗ рдЬреИрд╕реЗ рд╕реЙрдХреЗрдЯреНрд╕ рдкрд░ рд╕рдВрдЪрд╛рд▓рди рдЕрд╡рд░реБрджреНрдз рд╣реЛ рд░рд╣рд╛ рд╣реИ, рдЕрд░реНрдерд╛рдд, рдЬрдм рддрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдбреЗрдЯрд╛ рднреЗрдЬрдиреЗ рдХрд╛ рдХрд╛рдо рдкреВрд░рд╛ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рддрдм рддрдХ PHP рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдЧрд╛ред рдПрдХ рд╡реЗрдм рд╕рд░реНрд╡рд░ рдХреЗ рд▓рд┐рдП, рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИ: рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рд╕рдордп рдореЗрдВ рдПрдХ рдЕрдиреБрд░реЛрдз рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рд╕рдорд╛рдзрд╛рди рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдореЗрдВ рд╕реЙрдХреЗрдЯ рд╕реЗ рдкреВрдЫрдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдХреНрдпрд╛ рдпрд╣ рдбреЗрдЯрд╛ рдкрдврд╝рдиреЗ рдпрд╛ рд▓рд┐рдЦрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ "рддреИрдпрд╛рд░" рд╣реИред рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХреМрди рд╕реЗ рд╕реЙрдХреЗрдЯ рдбреЗрдЯрд╛ рднреЗрдЬрдиреЗ рдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВ, рд╣рдо stream_select() рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред

рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдЗрдП рдХреБрдЫ рдирдП рд╕рд┐рд╕реНрдХреЛрд▓реНрд╕ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рдЬреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реЙрдХреЗрдЯ рднреЗрдЬреЗрдВрдЧреЗ рдЬреЛ рдпрд╛ рддреЛ рдкрдврд╝рдиреЗ рдпрд╛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдВрддрдЬрд╛рд░ рдХрд░ рд░рд╣рд╛ рд╣реИ:
 function waitForRead($socket) { return new SystemCall( function(Task $task, Scheduler $scheduler) use ($socket) { $scheduler->waitForRead($socket, $task); } ); } function waitForWrite($socket) { return new SystemCall( function(Task $task, Scheduler $scheduler) use ($socket) { $scheduler->waitForWrite($socket, $task); } ); } 


рдпреЗ рд╕рд┐рд╕реНрдХреЛрд▓реНрд╕ рдЗрд╕реА рдЕрдиреБрд╕реВрдЪрдХ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдореАрдкрд╡рд░реНрддреА рд╣реИрдВ:
 <?php // resourceID => [socket, tasks] protected $waitingForRead = []; protected $waitingForWrite = []; public function waitForRead($socket, Task $task) { if (isset($this->waitingForRead[(int) $socket])) { $this->waitingForRead[(int) $socket][1][] = $task; } else { $this->waitingForRead[(int) $socket] = [$socket, [$task]]; } } public function waitForWrite($socket, Task $task) { if (isset($this->waitingForWrite[(int) $socket])) { $this->waitingForWrite[(int) $socket][1][] = $task; } else { $this->waitingForWrite[(int) $socket] = [$socket, [$task]]; } } 


waitingForRead рдФрд░ waitingForWrite рдмрд╕ рдЗрдВрддрдЬрд╝рд╛рд░ рдХрд░ рд░рд╣реЗ рд╕реЙрдХреЗрдЯреНрд╕ рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдп рд╣реИрдВред рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рд╣рд┐рд╕реНрд╕рд╛ рдпрд╣ рд╡рд┐рдзрд┐ рд╣реИ, рдЬреЛ рдпрд╣ рдЬрд╛рдВрдЪрддреА рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╕реЙрдХреЗрдЯ рддреИрдпрд╛рд░ рд╣реИрдВ рдФрд░ рдЙрдирдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИ:
 protected function ioPoll($timeout) { $rSocks = []; foreach ($this->waitingForRead as list($socket)) { $rSocks[] = $socket; } $wSocks = []; foreach ($this->waitingForWrite as list($socket)) { $wSocks[] = $socket; } $eSocks = []; // dummy if (!stream_select($rSocks, $wSocks, $eSocks, $timeout)) { return; } foreach ($rSocks as $socket) { list(, $tasks) = $this->waitingForRead[(int) $socket]; unset($this->waitingForRead[(int) $socket]); foreach ($tasks as $task) { $this->schedule($task); } } foreach ($wSocks as $socket) { list(, $tasks) = $this->waitingForWrite[(int) $socket]; unset($this->waitingForWrite[(int) $socket]); foreach ($tasks as $task) { $this->schedule($task); } } } 


stream_select рдлрд╝рдВрдХреНрд╢рди рд╕реЙрдХреЗрдЯ рдХреЗ рдЗрдирдкреБрдЯ рдПрд░реЗ рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ рдЬреЛ рдкрдврд╝рдиреЗ, рд▓рд┐рдЦреЗ рдЬрд╛рдиреЗ рдФрд░ рдлреЗрдВрдХреЗ рдЬрд╛рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдореЗрдВ рд╣реИ (рдмрд╛рдж рд╡рд╛рд▓реЗ рдХреЛ рдЕрдирджреЗрдЦрд╛ рдХрд░реЗрдВ)ред рдПрд░реЗ рдХреЛ рд╕рдВрджрд░реНрдн рджреНрд╡рд╛рд░рд╛ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХреЗрд╡рд▓ рдЙрди рддрддреНрд╡реЛрдВ рдХреЛ рдЫреЛрдбрд╝ рджреЗрдЧрд╛ рдЬрд┐рдирдХреА рд╕реНрдерд┐рддрд┐ рдмрджрд▓ рдЧрдИ рд╣реИред рдЙрд╕рдХреЗ рдмрд╛рдж рд╣рдо рдЗрди рд╕рднреА рд╕рд░рдгрд┐рдпреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрди рд╕реЙрдХреЗрдЯреНрд╕ рд╕реЗ рдЬреБрдбрд╝реЗ рд╕рднреА рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкреБрдирд░реНрдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдЗрди рд╕рднреА рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдзрд┐ рдХреЛ рдЕрдиреБрд╕реВрдЪрдХ рдореЗрдВ рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗ:
 protected function ioPollTask() { while (true) { if ($this->taskQueue->isEmpty()) { $this->ioPoll(null); } else { $this->ioPoll(0); } yield; } } 


рдЗрд╕ рдХрд╛рд░реНрдп рдХреЛ рдХреБрдЫ рдмрд┐рдВрджреБ рдкрд░ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдЖрдк $this->newTask($this->ioPollTask()) рдЬреЛрдбрд╝ рд╕рдХрддреЗ $this->newTask($this->ioPollTask()) run() рдХреЗ рд╢реАрд░реНрд╖ run() рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдПред рдлрд┐рд░ рдпрд╣ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдХрд╛рд░реНрдп рдХреА рддрд░рд╣ рдХрд╛рдо рдХрд░реЗрдЧрд╛, рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмреАрдЪ рдкреНрд░рддреНрдпреЗрдХ рд╕реНрд╡рд┐рдЪрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рддреИрдпрд╛рд░ рд╕реЙрдХреЗрдЯреНрд╕ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ред ioPollTask рдкрджреНрдзрддрд┐ рд╢реВрдиреНрдп рдЯрд╛рдЗрдордЖрдЙрдЯ рдХреЗ рд╕рд╛рде ioPoll рдХреЛ рдХреЙрд▓ ioPoll , рдЗрд╕рд▓рд┐рдП stream_select рдмрд┐рдирд╛ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд┐рдП рддреБрд░рдВрдд рдкрд░рд┐рдгрд╛рдо рд╡рд╛рдкрд╕ рдХрд░ рджреЗрдЧреАред

рдХреЗрд╡рд▓ рдЕрдЧрд░ рдХрд╛рд░реНрдп рдХрддрд╛рд░ рдЦрд╛рд▓реА рд╣реИ, рддреЛ рд╣рдо рд╕рдордп-рд╕реАрдорд╛ рдХреЗ рд░реВрдк рдореЗрдВ null рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ stream_select рдЗрдВрддрдЬрд╛рд░ рдХрд░реЗрдВрдЧреЗ рдЬрдм рддрдХ рдХрд┐ рд╕реЙрдХреЗрдЯреНрд╕ рдореЗрдВ рд╕реЗ рдХреЛрдИ рднреА рддреИрдпрд╛рд░ рди рд╣реЛред рдпрджрд┐ рд╣рдордиреЗ рдРрд╕рд╛ рдирд╣реАрдВ рдХрд┐рдпрд╛, рддреЛ рд╣рдо рдкреВрд░рд╛ рд╕реАрдкреАрдпреВ (рдХрдо рд╕реЗ рдХрдо рдХреЛрд░) рдЦрд╛рдПрдВрдЧреЗ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдХрд╛рд░реНрдп рдПрдХ рд▓реВрдк рдореЗрдВ рдмрд╛рд░-рдмрд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрдм рддрдХ рдХрд┐ рдХреЛрдИ рдЬреБрдбрд╝рд╛ рдирд╣реАрдВред

рд╕рд░реНрд╡рд░ рд╕реНрд╡рдпрдВ рдмрд╣реБрдд рд╕рд░рд▓ рджрд┐рдЦрддрд╛ рд╣реИ:
 function server($port) { echo "Starting server at port $port...\n"; $socket = @stream_socket_server("tcp://localhost:$port", $errNo, $errStr); if (!$socket) throw new Exception($errStr, $errNo); stream_set_blocking($socket, 0); while (true) { yield waitForRead($socket); $clientSocket = stream_socket_accept($socket, 0); yield newTask(handleClient($clientSocket)); } } function handleClient($socket) { yield waitForRead($socket); $data = fread($socket, 8192); $msg = "Received following request:\n\n$data"; $msgLength = strlen($msg); $response = <<<RES HTTP/1.1 200 OK\r Content-Type: text/plain\r Content-Length: $msgLength\r Connection: close\r \r $msg RES; yield waitForWrite($socket); fwrite($socket, $response); fclose($socket); } $scheduler = new Scheduler; $scheduler->newTask(server(8000)); $scheduler->run(); 


рдпрд╣ рдкреЛрд░реНрдЯ 8000 рдкрд░ рдХрдиреЗрдХреНрд╢рди рд╕реНрд╡реАрдХрд╛рд░ рдХрд░реЗрдЧрд╛ рдФрд░ рдХреЗрд╡рд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдЕрдиреБрд░реЛрдз рдХреА рд╕рд╛рдордЧреНрд░реА рднреЗрдЬреЗрдЧрд╛ред рдХреБрдЫ "рд╡рд╛рд╕реНрддрд╡рд┐рдХ" рдХрд░рдирд╛ рд╕рд╣реА рд╣реЛрдЧрд╛ (HTTP рдЕрдиреБрд░реЛрдзреЛрдВ рдХрд╛ рд╕рд╣реА рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рд╡рд┐рд╖рдп рдирд╣реАрдВ рд╣реИ)ред

рдЕрдм рдЖрдк рдЗрд╕ рд╕рд░реНрд╡рд░ рдХреЛ ab -n 10000 -c 100 localhost:8000/ рдЬреИрд╕реА рдХрд┐рд╕реА рдЪреАрдЬ рдХреЗ рд╕рд╛рде рдЯреЗрд╕реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рддреЛ рд╣рдо 10000 рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВрдЧреЗ, рдЬрд┐рдирдореЗрдВ рд╕реЗ 100 рдЙрд╕реА рд╕рдордп рднреЗрдЬреЗ рдЬрд╛рдПрдВрдЧреЗред рдЗрд╕ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдореБрдЭреЗ 10 рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдХреА рдФрд╕рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдорд┐рд▓реАред рд▓реЗрдХрд┐рди рдХреБрдЫ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╕рдорд╕реНрдпрд╛ рдереА рдЬрд┐рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдмрд╣реБрдд рд╕рдордп рд▓рдЧрд╛ (5 рд╕реЗрдХрдВрдб рдореЗрдВ рдЬрд┐рд▓рд╛), рдЗрд╕рд▓рд┐рдП рдХреБрд▓ рдереНрд░реВрдкреБрдЯ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рдХреЗрд╡рд▓ 2000 рдЕрдиреБрд░реЛрдз рд╣реИрдВред рдЙрдЪреНрдЪ рдкреНрд░рддрд┐рдпреЛрдЧрд┐рддрд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, -c 500 ) рдХреЗ рд╕рд╛рде, рд╕реНрдХреНрд░рд┐рдкреНрдЯ рднреА рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдХреБрдЫ рдХрдиреЗрдХреНрд╢рди "рд╕рд╣рдХрд░реНрдореА рджреНрд╡рд╛рд░рд╛ рд░реАрд╕реЗрдЯ рд░реАрд╕реЗрдЯ" рддреНрд░реБрдЯрд┐ рдлреЗрдВрдХрддреЗ рд╣реИрдВред

рджреВрд░рд╕реНрде рдХреЛрд░рдЯрд╛рдЗрди


рдпрджрд┐ рдЖрдк рд╣рдорд╛рд░реЗ рдЕрдиреБрд╕реВрдЪрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдмрдбрд╝реА рдкреНрд░рдгрд╛рд▓реА рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдЬрд▓реНрдж рд╣реА рдПрдХ рд╕рдорд╕реНрдпрд╛ рдореЗрдВ рдЖ рдЬрд╛рдПрдВрдЧреЗ: рд╣рдо рдЕрдХреНрд╕рд░ рдХреБрдЫ рдЯреБрдХрдбрд╝реЛрдВ рдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рд▓рдЧрд╛рдХрд░ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХреЙрд▓ рдХрд░рдХреЗ рдХреЛрдб рдХреЛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди coroutines рдХреЗ рд╕рд╛рде рдпрд╣ рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИред рдЗрд╕ рдХреЛрдб рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ:
 function echoTimes($msg, $max) { for ($i = 1; $i <= $max; ++$i) { echo "$msg iteration $i\n"; yield; } } function task() { echoTimes('foo', 10); // print foo ten times echo "---\n"; echoTimes('bar', 5); // print bar five times yield; // force it to be a coroutine } $scheduler = new Scheduler; $scheduler->newTask(task()); $scheduler->run(); 


рдЗрд╕ рдХреЛрдб рдореЗрдВ рд╣рдордиреЗ task() рд╕реЗ рдХреЛрд░рдЯрд╛рдЗрди рдирд┐рдХрд╛рд▓рдиреЗ рдФрд░ рдЙрд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ред рд▓реЗрдХрд┐рди рд╡рд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛редрдЬреИрд╕рд╛ рдХрд┐ рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдХрд╣рд╛ рдЧрдпрд╛ рдерд╛, рдЬрдирд░реЗрдЯрд░ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╕реЗ рдЗрд╕рдореЗрдВ рдХреЛрдИ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдХреНрд▓рд╛рд╕ рдСрдмреНрдЬреЗрдХреНрдЯ рд╡рд╛рдкрд╕ рдХрд░реЗрдЧрд╛ Generatorред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣реА рд╣реЛрддрд╛ рд╣реИ, рдХреЙрд▓ echoTimes()рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ, рд╡реЗ рдХреЗрд╡рд▓ рдСрдмреНрдЬреЗрдХреНрдЯ рд╡рд╛рдкрд╕ рдХрд░реЗрдВрдЧреЗред

рдЗрд╕рдХреЗ рд▓рд┐рдП рдмрд╛рд╣рд░ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдХреЛрд░рдЖрдЙрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рдЫреЛрдЯрд╛ рдЖрд╡рд░рдг рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ред рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╣рдо рдЙрдк-рдХреЙрд░рдЖрдЙрдЯ рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
 $retval = (yield someCoroutine($foo, $bar)); 

рдЙрдк-рдХреЛрд░рдЖрдЙрдЯреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдорд╛рди рднреА рд▓реМрдЯрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ yield:
 yield retval("I'm return value!"); 

рдлрд╝рдВрдХреНрд╢рди retval()рдорд╛рди рдкрд░ рдПрдХ рдЖрд╡рд░рдг рдХреЛ рдЫреЛрдбрд╝рдХрд░ рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рд╣рдореЗрдВ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд╛рдкрд╕реА рдореВрд▓реНрдп рд╣реИ:
 class CoroutineReturnValue { protected $value; public function __construct($value) { $this->value = $value; } public function getValue() { return $this->value; } } function retval($value) { return new CoroutineReturnValue($value); } 


рдПрдХ рдирд┐рдпрдорд┐рдд рдХреЛрд░рдЖрдЙрдЯ рд╕реЗ рдПрдХ рдорд┐рд╢реНрд░рд┐рдд рдХреЛрд░рдЖрдЙрдЯ (рдЙрдк-рдХреЛрд░рдЖрдЙрдЯ рдХреЗ рд╕рд╛рде) рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдФрд░ рдХрд╛рд░реНрдп рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ (рдЬреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдПрдХ рдФрд░ рдХреЛрд░рдЖрдЙрдЯ рд╣реИ):
 function stackedCoroutine(Generator $gen) { $stack = new SplStack; for (;;) { $value = $gen->current(); if ($value instanceof Generator) { $stack->push($gen); $gen = $value; continue; } $isReturnValue = $value instanceof CoroutineReturnValue; if (!$gen->valid() || $isReturnValue) { if ($stack->isEmpty()) { return; } $gen = $stack->pop(); $gen->send($isReturnValue ? $value->getValue() : NULL); continue; } $gen->send(yield $gen->key() => $value); } } 


рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХреЙрд▓рд░ рдФрд░ рдЪрд▓ рд░рд╣реЗ рдЙрдк-рдХреЛрд░рдЖрдЙрдЯ рдХреЗ рдмреАрдЪ рдПрдХ рд╕рд░рд▓ рдкреНрд░реЙрдХреНрд╕реА рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред рдпрд╣ рднреА рдЬрд╛рдВрдЪрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╡рд╛рдкрд╕реА рдореВрд▓реНрдп рднреА рдПрдХ рдЬрдирд░реЗрдЯрд░ рд╣реИ рдФрд░ рдпрджрд┐ рд╣рд╛рдВ, рддреЛ рдЗрд╕реЗ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИред рдЬрдм рд╡рд╣ рд╡рд╕реНрддреБ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреА рд╣реИ CoroutineReturnValue, рддреЛ рд╡рд╣ рдорд╛рддрд╛-рдкрд┐рддрд╛ рдХреЛ рдХреЛрд░рдЯрд╛рдЗрди рд▓реЗрдЧреА рдФрд░ рдЗрд╕рдХрд╛ рдирд┐рд╖реНрдкрд╛рджрди рдЬрд╛рд░реА рд░рдЦреЗрдЧреАред

рддрд╛рдХрд┐ рдпреМрдЧрд┐рдХ рдХреЛрд░рдЯрд╛рдЗрди рдХреЛ рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ, $this->coroutine = $coroutine;рд╡рд░реНрдЧ рдирд┐рд░реНрдорд╛рдгрдХрд░реНрддрд╛ рдХреА рдкрдВрдХреНрддрд┐ рдХреЛ рдЗрд╕рдХреЗ Taskрд╕рд╛рде рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛$this->coroutine = stackedCoroutine($coroutine); ред

рдЕрдм рд╣рдо рдкрдврд╝рдиреЗ, рд▓рд┐рдЦрдиреЗ рдФрд░ рдПрдХ рдирдпрд╛ рдХрдиреЗрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕рдореВрд╣реАрдХреГрдд рдХрд░рдХреЗ рдЕрдкрдиреЗ рд╡реЗрдм рд╕рд░реНрд╡рд░ рдХреЛ рдереЛрдбрд╝рд╛ рд╕реБрдзрд╛рд░ рд╕рдХрддреЗ рд╣реИрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрд╕ рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
 class CoSocket { protected $socket; public function __construct($socket) { $this->socket = $socket; } public function accept() { yield waitForRead($this->socket); yield retval(new CoSocket(stream_socket_accept($this->socket, 0))); } public function read($size) { yield waitForRead($this->socket); yield retval(fread($this->socket, $size)); } public function write($string) { yield waitForWrite($this->socket); fwrite($this->socket, $string); } public function close() { @fclose($this->socket); } } 


рдЕрдм рд╕рд░реНрд╡рд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
 function server($port) { echo "Starting server at port $port...\n"; $socket = @stream_socket_server("tcp://localhost:$port", $errNo, $errStr); if (!$socket) throw new Exception($errStr, $errNo); stream_set_blocking($socket, 0); $socket = new CoSocket($socket); while (true) { yield newTask( handleClient(yield $socket->accept()) ); } } function handleClient($socket) { $data = (yield $socket->read(8192)); $msg = "Received following request:\n\n$data"; $msgLength = strlen($msg); $response = <<<RES HTTP/1.1 200 OK\r Content-Type: text/plain\r Content-Length: $msgLength\r Connection: close\r \r $msg RES; yield $socket->write($response); yield $socket->close(); } 


рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдореЗрдВ рддреНрд░реБрдЯрд┐


рдПрдХ рдЕрдЪреНрдЫреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рд░реВрдк рдореЗрдВ, рдЖрдкрдиреЗ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рджреЗрдЦрд╛ рд╣реИ рдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдХреА рдХрдореА рд╣реИред рд╕реЙрдХреЗрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдХреЛрдИ рднреА рдСрдкрд░реЗрд╢рди рд╣рдореЗрд╢рд╛ рддреНрд░реБрдЯрд┐ рдореЗрдВ рдкрдбрд╝ рд╕рдХрддрд╛ рд╣реИред рдореИрдВрдиреЗ рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рдХрд┐рдпрд╛ рдХреНрдпреЛрдВрдХрд┐ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП рддреНрд░реБрдЯрд┐ рд╕реЗ рдирд┐рдкрдЯрдирд╛ рдмрд╣реБрдд рдердХрд╛рдК рд╣реЛрддрд╛ рд╣реИ (рд╡рд┐рд╢реЗрд╖рдХрд░ рд╕реЙрдХреЗрдЯ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ) рдФрд░ рдпрд╣ рдХрдИ рдмрд╛рд░ рд╣рдорд╛рд░реЗ рдХреЛрдб рдХреЛ рдмрдврд╝рд╛рддрд╛ рд╣реИред

рд▓реЗрдХрд┐рди, рдлрд┐рд░ рднреА, рдореИрдВ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ coroutines рдХреЗ рд▓рд┐рдП рддреНрд░реБрдЯрд┐ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛: coroutines рдЖрдкрдХреЛ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрдирдХреЗ рдЕрдВрджрд░ рдЕрдкрд╡рд╛рдж рдлреЗрдВрдХрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ throw()ред

рд╡рд┐рдзрд┐ throw()рдкрд╣рд▓реЗ рддрд░реНрдХ рдореЗрдВ рдПрдХ рдЕрдкрд╡рд╛рдж рд▓реЗрддреА рд╣реИ рдФрд░ рдЗрд╕реЗ рдЙрд╕ рд╕реНрдерд╛рди рдкрд░ рдлреЗрдВрдХрддреА рд╣реИ рдЬрд╣рд╛рдВ рд╡рд░реНрддрдорд╛рди рдЙрдкрдЬ рд╣реИ (рдЬрд┐рд╕рдХрд╛ рдореВрд▓реНрдп рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ current()):
 function gen() { echo "Foo\n"; try { yield; } catch (Exception $e) { echo "Exception: {$e->getMessage()}\n"; } echo "Bar\n"; } $gen = gen(); $gen->rewind(); // echos "Foo" $gen->throw(new Exception('Test')); // echos "Exception: Test" // and "Bar" 


рдпрд╣ рдПрдХ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рдмрд╛рдд рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдо рдЕрдкрд╡рд╛рджреЛрдВ рдХреЛ рдлреЗрдВрдХрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд┐рд╕реНрдХреЛрд▓ рдФрд░ рдЙрдк-рдХреЙрд░рдЯрд╛рдЗрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрд╡рд╕рд░ рджреЗ рд╕рдХрддреЗ рд╣реИрдВред рд╕рд┐рд╕реНрдХреЛрд▓ рдХреЗ рд▓рд┐рдП, рд╡рд┐рдзрд┐ Scheduler::run()рдХреЛ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
 if ($retval instanceof SystemCall) { try { $retval($task, $this); } catch (Exception $e) { $task->setException($e); $this->schedule($task); } continue; } 


рдФрд░ рдХрдХреНрд╖рд╛ TaskрдХреЛ рдХреЙрд▓ рд╕рдВрднрд╛рд▓рдиреА рдЪрд╛рд╣рд┐рдП throw():
 class Task { // ... protected $exception = null; public function setException($exception) { $this->exception = $exception; } public function run() { if ($this->beforeFirstYield) { $this->beforeFirstYield = false; return $this->coroutine->current(); } elseif ($this->exception) { $retval = $this->coroutine->throw($this->exception); $this->exception = null; return $retval; } else { $retval = $this->coroutine->send($this->sendValue); $this->sendValue = null; return $retval; } } // ... } 


рдЕрдм рд╣рдо рд╕рд┐рд╕реНрдХреЛрд▓ рд╕реЗ рдЕрдкрд╡рд╛рдж рдлреЗрдВрдХрдирд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ! рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, killTaskрдпрджрд┐ рдПрдХ рдЯреНрд░рд╛рдВрд╕рдорд┐рдЯреЗрдб рдЯрд╛рд╕реНрдХ рдЖрдЗрдбреЗрдВрдЯрд┐рдлрд╝рд╛рдпрд░ рдЕрдорд╛рдиреНрдп рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдЕрдкрд╡рд╛рдж рдЫреЛрдбрд╝ рджреЗрдВ:
 function killTask($tid) { return new SystemCall( function(Task $task, Scheduler $scheduler) use ($tid) { if ($scheduler->killTask($tid)) { $scheduler->schedule($task); } else { throw new InvalidArgumentException('Invalid task ID!'); } } ); } 


рдЕрдм рдЪрд▓реЛ рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ:
 function task() { try { yield killTask(500); } catch (Exception $e) { echo 'Tried to kill task 500 but failed: ', $e->getMessage(), "\n"; } } 


рдЕрдм рддрдХ рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рдЬреИрд╕рд╛ рдХрд┐ рдлрд╝рдВрдХреНрд╢рди stackedCoroutineрдЕрдкрд╡рд╛рджреЛрдВ рдХреЛ рдирд╣реАрдВ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИред рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрд╕реЗ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░реЗрдВ:
 function stackedCoroutine(Generator $gen) { $stack = new SplStack; $exception = null; for (;;) { try { if ($exception) { $gen->throw($exception); $exception = null; continue; } $value = $gen->current(); if ($value instanceof Generator) { $stack->push($gen); $gen = $value; continue; } $isReturnValue = $value instanceof CoroutineReturnValue; if (!$gen->valid() || $isReturnValue) { if ($stack->isEmpty()) { return; } $gen = $stack->pop(); $gen->send($isReturnValue ? $value->getValue() : NULL); continue; } try { $sendValue = (yield $gen->key() => $value); } catch (Exception $e) { $gen->throw($e); continue; } $gen->send($sendValue); } catch (Exception $e) { if ($stack->isEmpty()) { throw $e; } $gen = $stack->pop(); $exception = $e; } } } 


рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рджреЗрдирд╛


рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдордиреЗ рд╕рдВрдпреБрдХреНрдд рдорд▓реНрдЯреАрдЯрд╛рд╕реНрдХрд┐рдВрдЧ, рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рднреЗрдЬрдиреЗ рдХреА рдХреНрд╖рдорддрд╛, рдЧреИрд░-рдЕрд╡рд░реБрджреНрдз рд╕рдВрдЪрд╛рд▓рди рдФрд░ рддреНрд░реБрдЯрд┐ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реБрдП рдПрдХ рдХрд╛рд░реНрдп рдЕрдиреБрд╕реВрдЪрдХ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд┐рдпрд╛ред рдЗрд╕ рд╕рдм рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫреА рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдЕрдВрддрд┐рдо рдХреЛрдб рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рд┐рдВрдХреНрд░реЛрдирд╕ рджрд┐рдЦрддрд╛ рд╣реИ, рднрд▓реЗ рд╣реА рдпрд╣ рдХрдИ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╕рдВрдЪрд╛рд▓рди рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ рд╕реЙрдХреЗрдЯ рд╕реЗ рдбреЗрдЯрд╛ рдкрдврд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдХреЙрд▓рдмреИрдХ рднреЗрдЬрдиреЗ рдпрд╛ рд╢реНрд░реЛрддрд╛ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рдЖрдк рд▓рд┐рдЦрддреЗ рд╣реИрдВ yield $socket->read()ред

рдЬрдм рдореИрдВрдиреЗ рдкрд╣рд▓реА рдмрд╛рд░ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реБрдирд╛, рддреЛ рдореБрдЭреЗ рдПрд╣рд╕рд╛рд╕ рд╣реБрдЖ рдХрд┐ рдпрд╣ рдХрд┐рддрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реИ, рдФрд░ рдЗрд╕рдиреЗ рдореБрдЭреЗ рдЙрдиреНрд╣реЗрдВ PHP рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрд░рд┐рдд рдХрд┐рдпрд╛ред рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдбрд░рд╛рд╡рдиреЗ рд╣реИрдВред рд╢рд╛рдВрдд рдХреЛрдб рдФрд░ рдЦреМрдлрдирд╛рдХ рдЧрдВрджрдЧреА рдХреЗ рдмреАрдЪ рдПрдХ рдорд╣реАрди рд░реЗрдЦрд╛ рд╣реИ, рдФрд░ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрд╕ рд▓рд╛рдЗрди рдкрд░ рдХреЛрд░рдЯрд╛рдЗрди рд╣реИрдВред рдореЗрд░реЗ рд▓рд┐рдП рдпрд╣ рдХрд╣рдирд╛ рдХрдард┐рди рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХреЛрд░рдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛, рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рд╣реИ, рдХрд┐рд╕реА рддрд░рд╣ рд╕реЗ рдлрд╛рдпрджреЗрдордВрдж рд╣реИред

рдХрд┐рд╕реА рднреА рдорд╛рдорд▓реЗ рдореЗрдВ, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдмрд╣реБрдд рд╣реА рджрд┐рд▓рдЪрд╕реНрдк рд╡рд┐рд╖рдп рд╣реИ, рдФрд░ рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЖрдк рднреА :)

рдЕрдиреБрд╡рд╛рджрдХ рд╕реЗ рдкреБрдирд╢реНрдЪ: рд▓реЗрдЦ рдмрд╣реБрдд рдмрдбрд╝рд╛ рд╣реИ рдФрд░ рд╕рдордЭрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕рдореЗрдВ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ, рдЬрд┐рдирдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ рдЕрд░реНрдеред рдЕрдЧрд░ рдЖрдкрдиреЗ рдпрд╣ рджреЗрдЦрд╛ - рдХреГрдкрдпрд╛ рднреЗрдЬреЗрдВред

Source: https://habr.com/ru/post/In164173/


All Articles