PCS2020 - PHP Além do Síncrono

4ce43cd2535d0afe50065a743af646e9?s=47 Diana Arnos
September 12, 2020

PCS2020 - PHP Além do Síncrono

Apresentada durante o PHP Community Summit de 2020.

Quando tudo era mato, ninguém acreditava que a linguagem PHP poderia ser usada para nada além da execução de scripts simples, sites ou um CMS de código bem bagunçado.
Então o mundo mudou e hoje temos grandes frameworks, sistemas corporativos, grandes portais e redes sociais e até sistemas de segurança e pagamentos escritos em PHP.
Agora, a comunidade se debruça sobre o novo hype (ou seria necessidade?): processamento assíncrono e paralelo.
Nessa apresentação, vamos entender a difereça entre async e paralelo, como podemos trabalhar com isso usando PHP (inclusive nativamente) e quais as principais diferenças entre as soluções mais hypadas (digo, famosas) do momento.

4ce43cd2535d0afe50065a743af646e9?s=128

Diana Arnos

September 12, 2020
Tweet

Transcript

  1. PHP Além do Síncrono O reino mágico do processamento async

    e paralelo
  2. @dianaarnos Dev, Sec, Music, Kung Fu. PHP Engineer @ Usabilla

    (Amsterdã, Holanda) (soon) Evangelista @ PHPSP Evangelista @ PHPWomenBR
  3. None
  4. PHP é síncrono

  5. PHP é síncrono Mas dá pra trabalhar assíncrono

  6. PHP é síncrono Mas dá pra trabalhar assíncrono Não é

    pra isso que serve!
  7. PHP é síncrono Mas dá pra trabalhar assíncrono Não é

    pra isso que serve! Se funciona, então serve
  8. PHP é síncrono Mas dá pra trabalhar assíncrono Não é

    pra isso que serve! Se funciona, então serve M AS E O SHARE NOTHING?!
  9. PHP é síncrono Mas dá pra trabalhar assíncrono Não é

    pra isso que serve! Se funciona, então serve M AS E O SHARE NOTHING?! M AS É O UTRO CO NTEXTO !
  10. None
  11. Calma, xovem. É muita emoção.

  12. None
  13. Síncrono Requests Tempo Task #1 Task #2 Task #3

  14. Assíncrono Requests Tempo Task #1 Task #2 Task #3 Task

    #1 Task #3
  15. Paralelo Requests Tempo Task #1 Task #2 Task #3 Task

    #1 Task #3 Task #2 Task #1 Task #2 Task #3
  16. Paralelismo e Assíncronismo = Concorrência

  17. Concorrência no PHP?

  18. None
  19. None
  20. None
  21. Ext Parallel

  22. Ext Parallel - ZTS

  23. use parallel\Runtime; $runtime = new Runtime(); $future = $runtime->run(function(){ for

    ($i = 0; $i < 100; $i++) echo "*"; return "fácil"; }); for ($i = 0; $i < 100; $i++) { echo "."; } printf("\nUsar o \\parallel\\Runtime é %s\n", $future->value());
  24. Parallel x Swoole Swoole implements co-operative multi-tasking, and if you

    were following along, you already figured out that this is not based on parallel concurrency, but on asynchronous concurrency. When the readme says "you can think of co-routines as individual threads", it's referring to green threads. No user code is executed in parallel, it is executed asynchronously. The internals of swoole does use threads but to service I/O, not to execute user code. - Joe Watkins (krakjoe)
  25. PHP é síncrono. Realmente.

  26. <?php echo PHP_EOL . "Step 1" . PHP_EOL; for ($i

    = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Step 2" . PHP_EOL; for ($i = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Finish." . PHP_EOL;
  27. <?php echo PHP_EOL . "Step 1" . PHP_EOL; for ($i

    = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Step 2" . PHP_EOL; for ($i = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Finish." . PHP_EOL;
  28. <?php echo PHP_EOL . "Step 1" . PHP_EOL; for ($i

    = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Step 2" . PHP_EOL; for ($i = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Finish." . PHP_EOL;
  29. <?php echo PHP_EOL . "Step 1" . PHP_EOL; for ($i

    = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Step 2" . PHP_EOL; for ($i = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Finish." . PHP_EOL;
  30. <?php echo PHP_EOL . "Step 1" . PHP_EOL; for ($i

    = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Step 2" . PHP_EOL; for ($i = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Finish." . PHP_EOL;
  31. <?php echo PHP_EOL . "Step 1" . PHP_EOL; for ($i

    = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Step 2" . PHP_EOL; for ($i = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Finish." . PHP_EOL;
  32. <?php echo PHP_EOL . "Step 1" . PHP_EOL; for ($i

    = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Step 2" . PHP_EOL; for ($i = 0; $i <11; $i++) { echo "."; } echo PHP_EOL . "Finish." . PHP_EOL;
  33. Mas dá pra ser assíncrono também.

  34. Mas dá pra ser assíncrono também. Nativo.

  35. None
  36. Olá, generators!

  37. <?php $function = function () { yield PHP_EOL . "Starting";

    echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end." ; };
  38. $generator = $function(); echo PHP_EOL . "Main flow"; echo $generator->current();

    echo PHP_EOL . "Main flow"; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow"; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow"; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end." ; };
  39. <?php $function = function () { yield PHP_EOL . "Starting";

    echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; }; $generator = $function(); echo PHP_EOL . "Main flow" ; echo $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ;
  40. <?php $function = function () { yield PHP_EOL . "Starting";

    echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; }; $generator = $function(); echo PHP_EOL . "Main flow" ; echo $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ;
  41. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  42. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  43. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  44. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  45. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  46. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  47. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  48. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  49. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  50. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  51. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  52. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  53. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  54. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  55. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  56. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  57. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  58. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  59. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  60. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  61. $generator = $function(); echo PHP_EOL . "Main flow" ; echo

    $generator->current(); echo PHP_EOL . "Main flow" ; $generator->next(); echo $generator->current(); $generator->next(); echo PHP_EOL . "Main flow" ; $generator->send("aeeewww"); $generator->next(); echo $generator->getReturn() . PHP_EOL; echo PHP_EOL . "Main flow" ; <?php $function = function () { yield PHP_EOL . "Starting"; echo PHP_EOL . "-"; yield PHP_EOL . "."; $incoming = yield; echo PHP_EOL . $incoming; return PHP_EOL . "Generator's end."; };
  62. Prazer, corrotina.

  63. Mas… e requests?

  64. cURL

  65. cURL

  66. curl_multi_*

  67. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  68. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  69. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  70. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  71. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  72. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  73. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  74. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  75. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  76. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  77. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  78. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  79. $urls = ["http://dummy.restapiexample.com/api/v1/employee/1" , "http://dummy.restapiexample.com/api/v1/employee/2" ,]; $multiHandle = curl_multi_init() ;

    $curls = []; $results = []; $callback = function ($data) { echo $data . PHP_EOL; }; foreach ($urls as $url) { $handle = curl_init() ; curl_setopt_array( $handle, [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false]); $curls[$url] = $handle; curl_multi_add_handle( $multiHandle , $handle); } $isRunning = null; do { $multiCurlStatus = curl_multi_exec( $multiHandle , $isRunning); $resource = curl_multi_info_read( $multiHandle ); if ($resource) { $callback(curl_multi_getcontent( $resource['handle'])); curl_multi_remove_handle( $multiHandle , $resource['handle']); } } while ($multiCurlStatus == CURLM_CALL_MULTI_PERFORM || $isRunning);
  80. None
  81. Concorrência assíncrona :)

  82. Mas tem mais!

  83. I/O multiplexing com… stream_select

  84. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  85. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  86. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  87. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  88. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  89. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  90. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  91. $host = "dummy.restapiexample.com"; $resource = [ "api/v1/employee/1", "api/v1/employee/2", ]; $clients

    = []; foreach ($resource as $url) { $socketClient = stream_socket_client( 'tcp://' . $host . ':80', $errno, $errstr, 10, STREAM_CLIENT_ASYNC_CONNECT ); $clients[$url] = $socketClient; $request = "GET /" . $url . " HTTP/1.1" . PHP_EOL . "Host: " . $host . PHP_EOL . PHP_EOL; fwrite($socketClient, $request); stream_set_blocking($socketClient, 0); } stream_select($clients, $write, $ex, 10); if (count($clients)) { foreach ($clients as $id => $socket) { echo fread($socket, 2000); } }
  92. MAIS AINDA!

  93. MAIS AINDA! Eventos com stream context

  94. public function download () { $context = stream_context_create() ; stream_context_set_params(

    $context , ['notification' => [Downloader:: class, 'streamCallback' ]]); $handler = fopen( $this->youtube->getUrl(), 'r', false, $context ); if (!$handler ) { throw new \InvalidArgumentException( "Unable to download from link " . $this->youtube->getUrl()); } file_put_contents( $this->youtube->getName(), $handler ); } public function streamCallback ($notification_code , $severity , $message , $message_code , $bytes_transfered , $bytes_max ) { static $filesize = null; switch ($notification_code ) { case STREAM_NOTIFY_RESOLVE: case STREAM_NOTIFY_AUTH_REQUIRED: case STREAM_NOTIFY_COMPLETED: case STREAM_NOTIFY_FAILURE: case STREAM_NOTIFY_AUTH_RESULT: break; case STREAM_NOTIFY_REDIRECTED: echo "Being redirected to: " . $message . PHP_EOL; break; case STREAM_NOTIFY_CONNECT: echo "Connected!" . PHP_EOL; case STREAM_NOTIFY_FILE_SIZE_IS: $filesize = $bytes_max ; echo "Filesize: " . $filesize . PHP_EOL; case STREAM_NOTIFY_MIME_TYPE_IS: echo "Mime-type: " . $message . PHP_EOL; case STREAM_NOTIFY_PROGRESS: if ($bytes_transfered > 0) { $length = (int)(($bytes_transfered / $filesize ) * 100); printf("\r[%-100s] %d%% (%2d/%2d mb)" , str_repeat( "=", $length) . ">", $length, ($bytes_transfered / 1024 / 1024), $filesize / 1024 / 1024); } break; } }
  95. public function download () { $context = stream_context_create() ; stream_context_set_params(

    $context , ['notification' => [Downloader:: class, 'streamCallback' ]]); $handler = fopen( $this->youtube->getUrl(), 'r', false, $context ); if (!$handler ) { throw new \InvalidArgumentException( "Unable to download from link " . $this->youtube->getUrl()); } file_put_contents( $this->youtube->getName(), $handler ); } public function streamCallback ($notification_code , $severity , $message , $message_code , $bytes_transfered , $bytes_max ) { static $filesize = null; switch ($notification_code ) { case STREAM_NOTIFY_RESOLVE: case STREAM_NOTIFY_AUTH_REQUIRED: case STREAM_NOTIFY_COMPLETED: case STREAM_NOTIFY_FAILURE: case STREAM_NOTIFY_AUTH_RESULT: break; case STREAM_NOTIFY_REDIRECTED: echo "Being redirected to: " . $message . PHP_EOL; break; case STREAM_NOTIFY_CONNECT: echo "Connected!" . PHP_EOL; case STREAM_NOTIFY_FILE_SIZE_IS: $filesize = $bytes_max ; echo "Filesize: " . $filesize . PHP_EOL; case STREAM_NOTIFY_MIME_TYPE_IS: echo "Mime-type: " . $message . PHP_EOL; case STREAM_NOTIFY_PROGRESS: if ($bytes_transfered > 0) { $length = (int)(($bytes_transfered / $filesize ) * 100); printf("\r[%-100s] %d%% (%2d/%2d mb)" , str_repeat( "=", $length) . ">", $length, ($bytes_transfered / 1024 / 1024), $filesize / 1024 / 1024); } break; } }
  96. public function download () { $context = stream_context_create() ; stream_context_set_params(

    $context , ['notification' => [Downloader:: class, 'streamCallback' ]]); $handler = fopen( $this->youtube->getUrl(), 'r', false, $context ); if (!$handler ) { throw new \InvalidArgumentException( "Unable to download from link " . $this->youtube->getUrl()); } file_put_contents( $this->youtube->getName(), $handler ); } public function streamCallback ($notification_code , $severity , $message , $message_code , $bytes_transfered , $bytes_max ) { static $filesize = null; switch ($notification_code ) { case STREAM_NOTIFY_RESOLVE: case STREAM_NOTIFY_AUTH_REQUIRED: case STREAM_NOTIFY_COMPLETED: case STREAM_NOTIFY_FAILURE: case STREAM_NOTIFY_AUTH_RESULT: break; case STREAM_NOTIFY_REDIRECTED: echo "Being redirected to: " . $message . PHP_EOL; break; case STREAM_NOTIFY_CONNECT: echo "Connected!" . PHP_EOL; case STREAM_NOTIFY_FILE_SIZE_IS: $filesize = $bytes_max ; echo "Filesize: " . $filesize . PHP_EOL; case STREAM_NOTIFY_MIME_TYPE_IS: echo "Mime-type: " . $message . PHP_EOL; case STREAM_NOTIFY_PROGRESS: if ($bytes_transfered > 0) { $length = (int)(($bytes_transfered / $filesize ) * 100); printf("\r[%-100s] %d%% (%2d/%2d mb)" , str_repeat( "=", $length) . ">", $length, ($bytes_transfered / 1024 / 1024), $filesize / 1024 / 1024); } break; } }
  97. public function download () { $context = stream_context_create() ; stream_context_set_params(

    $context , ['notification' => [Downloader:: class, 'streamCallback' ]]); $handler = fopen( $this->youtube->getUrl(), 'r', false, $context ); if (!$handler ) { throw new \InvalidArgumentException( "Unable to download from link " . $this->youtube->getUrl()); } file_put_contents( $this->youtube->getName(), $handler ); } public function streamCallback ($notification_code , $severity , $message , $message_code , $bytes_transfered , $bytes_max ) { static $filesize = null; switch ($notification_code ) { case STREAM_NOTIFY_RESOLVE: case STREAM_NOTIFY_AUTH_REQUIRED: case STREAM_NOTIFY_COMPLETED: case STREAM_NOTIFY_FAILURE: case STREAM_NOTIFY_AUTH_RESULT: break; case STREAM_NOTIFY_REDIRECTED: echo "Being redirected to: " . $message . PHP_EOL; break; case STREAM_NOTIFY_CONNECT: echo "Connected!" . PHP_EOL; case STREAM_NOTIFY_FILE_SIZE_IS: $filesize = $bytes_max ; echo "Filesize: " . $filesize . PHP_EOL; case STREAM_NOTIFY_MIME_TYPE_IS: echo "Mime-type: " . $message . PHP_EOL; case STREAM_NOTIFY_PROGRESS: if ($bytes_transfered > 0) { $length = (int)(($bytes_transfered / $filesize ) * 100); printf("\r[%-100s] %d%% (%2d/%2d mb)" , str_repeat( "=", $length) . ">", $length, ($bytes_transfered / 1024 / 1024), $filesize / 1024 / 1024); } break; } }
  98. public function download () { $context = stream_context_create() ; stream_context_set_params(

    $context , ['notification' => [Downloader:: class, 'streamCallback' ]]); $handler = fopen( $this->youtube->getUrl(), 'r', false, $context ); if (!$handler ) { throw new \InvalidArgumentException( "Unable to download from link " . $this->youtube->getUrl()); } file_put_contents( $this->youtube->getName(), $handler ); } public function streamCallback ($notification_code , $severity , $message , $message_code , $bytes_transfered , $bytes_max ) { static $filesize = null; switch ($notification_code ) { case STREAM_NOTIFY_RESOLVE: case STREAM_NOTIFY_AUTH_REQUIRED: case STREAM_NOTIFY_COMPLETED: case STREAM_NOTIFY_FAILURE: case STREAM_NOTIFY_AUTH_RESULT: break; case STREAM_NOTIFY_REDIRECTED: echo "Being redirected to: " . $message . PHP_EOL; break; case STREAM_NOTIFY_CONNECT: echo "Connected!" . PHP_EOL; case STREAM_NOTIFY_FILE_SIZE_IS: $filesize = $bytes_max ; echo "Filesize: " . $filesize . PHP_EOL; case STREAM_NOTIFY_MIME_TYPE_IS: echo "Mime-type: " . $message . PHP_EOL; case STREAM_NOTIFY_PROGRESS: if ($bytes_transfered > 0) { $length = (int)(($bytes_transfered / $filesize ) * 100); printf("\r[%-100s] %d%% (%2d/%2d mb)" , str_repeat( "=", $length) . ">", $length, ($bytes_transfered / 1024 / 1024), $filesize / 1024 / 1024); } break; } }
  99. Forks? pnct_*

  100. <?php $pid = pcntl_fork() ; if ($pid == -1) {

    die('could not fork' ); } else if ($pid) { // we are the parent pcntl_wait($status); //Protect against Zombie children } else { // we are the child }
  101. Só funciona em Linux

  102. Só funciona em Linux Limitado ao número de CPUs

  103. Fork != Thread

  104. - Concorrência paralela

  105. - Concorrência paralela - Concorrência assíncrona

  106. - Concorrência paralela - Concorrência assíncrona - Eventos

  107. - Concorrência paralela - Concorrência assíncrona - Eventos - Paralelização

  108. None
  109. Você tem seu próprio ReactPHP, Amp, etc...

  110. Ahhhh, mas se fosse Java...

  111. O PHP também faz.

  112. REFERÊNCIAS http://bit.ly/pcs2020-ref

  113. SLIDES http://bit.ly/pcs2020-slides

  114. JOIND.IN https://joind.in/talk/43ab3

  115. OBRIGADA! Fale comigo: @dianaarnos