php - How to make an asynchronous self-calling loop non-recursive -


i'm writing function in php loops through array, , performs asynchronous call on (using promise).

the problem that, way can make loop happen, letting function call asynchronously. run 100-nested functions problem quick, , change not recur.

function myloop($data, $index = 0) {      if (!isset($data[$index])) {         return;     }      $currentitem = $data[$index];     $currentitem()->then(function() use ($data, $index) {        myloop($data, $index + 1);        });  } 

for want answer practical perspective (e.g.: rewrite not asynchronous), i'm experimenting functional , asynchronous patterns , want know if possible php.

i've written possible solution in pseudo-code. idea limit number of items running asynchronous @ once using database queue. myloop() no longer directly recursive, instead being called whenever item finishes running. in sample data, i've limited 4 items concurrently (arbitrary value). basically, it's still recursively calling itself, in roundabout way, avoiding situation mentioned of many nested called.

execution flow:

myloop() ---> queue ^              v |              | '<-processor <-'   

<?php     //---------- // database  //table:  config //columns: setting, value //items:    active_count, 0 //          item_concurrent_max, 4 //table: queue //columns: id, item, data, index, pid, status(waiting, running, finished), locked //  --- end pseudo-schema ---  <?php     // --------------- // itemloop.php // ---------------  //sends item , associated data produced myloop() database queue, //to processed (run asynchronous, limited how many can run @ once)  function send_item_to_processor($item, $data, $index, $counter) {     //insert $item queue table, along $data, $index (if needed), $counter, locked = 0    //status == waiting }  //original code, modified remove direct recursion , implement  //the queue. function myloop($data, $index = 0, $counter = 0) {      if (!isset($data[$index])) {         return;     }      $currentitem = $data[$index];     $currentitem()->then(function() use ($data, $index) {        //instead of directly calling `myloop()`, push item        //database , let processor worry it. see below.        //*if wanted currentitem call specific function after finishing,        //you create array of numbered functions , pass function        //number along other data.*         send_item_to_processor($currentitem, $data, $index + 1, $counter + 1);     });  }   // --------------- // processor.php // ---------------  //handles actual running of items.  looks "waiting" item ,  //executes it, updating various statuses along way.  //*called `process_queue()`* function process_new_items() {     //select active_count, item_concurrent_max    //item_count = total records in queue. done    //short-circuit execution of `process_queue()` whenever possible    //(which called frequently).    if (item_count == 0 || $active_count >= $item_concurrent_max)       return false;    //select item queue status = waiting , locked = 0 limit 1;    //update item set status = running, pid = programpid    //update config active_count = +1    //**** asynchronous run item here ****//    return true; }    //main processor queue.  first processes new/waiting items //if can (if many items aren't running), processes //dead/completed items.  upon item.status == finished, `myloop()` //called function.  still technically recursive call,  //avoids out-of-control situations due asynchronous nature.     //this function called on timer of sort, such cronjob function process_queue() {   if (!process_new_items())      return false;  //too many instances running, no need process    //check queue table items status == finished or is_pid_valid(pid) == false   $numcomplete = count($rows);   //update rows locked = 1, in case process_queue() gets called again before   //we finish, resulting in item potentially being processed dead twice.    foreach($rows $item) {     if (is_invalid(pid) || $status == finished)  {         //and here call myloop(), avoiding strictly recursive         //function call.          //*not sure `$item` here -- might passed `myloop()`?.*        //delete item(s) queue        myloop(data, index, counter - 1);        //decrease config.active_count $numcomplete     }   } } 

Comments

Popular posts from this blog

javascript - RequestAnimationFrame not working when exiting fullscreen switching space on Safari -

jsf - How to ajax update an item in the footer of a PrimeFaces dataTable? -

jquery - Keeping Kendo Datepicker in min/max range -