title: Multi-threaded downloading files with Guzzle HTTP client: EachPromises vs Pool objects
body: <p>for testing purposes, I have an array of 2000 image URIs (strings) with I download asynchronously with this functions. After some googling &amp; testing &amp; trying I've come up with <strong>2 functions that both of them work</strong> (well to be honest <em>downloadFilesAsync2</em> throws a <em>InvalidArgumentException</em> at the last line).</p>
  
  <p>The function <em>downloadFilesAsync2</em> is based on the class <strong>GuzzleHttp\Promise\EachPromise</strong> and <em>downloadFilesAsync1</em> is based on the <strong>GuzzleHttp\Pool</strong> class.</p>
  
  <p>Both functions download pretty well the 2000 files asynchronously, with the limit of 10 threads at the same time.</p>
  
  <p>I know that they work, but nothing else. I wonder if someone could explain both aproaches, if one is better than the other, implications, etc.</p>
  
  <pre><code>// for the purpose of this question i've reduced the array to 5 files!
  $uris = array /
    "https://cdn.enchufix.com/media/catalog/product/u/n/unix-48120.jpg",
    "https://cdn.enchufix.com/media/catalog/product/u/n/unix-48120-01.jpg",
    "https://cdn.enchufix.com/media/catalog/product/u/n/unix-48120-02.jpg",
    "https://cdn.enchufix.com/media/catalog/product/u/n/unix-48120-03.jpg",
    "https://cdn.enchufix.com/media/catalog/product/u/n/unix-48120-04.jpg",
  );
  
  function downloadFilesAsync2(array $uris, string $dir, $overwrite=true) {
      $client   = new \GuzzleHttp\Client();
      $requests = array();
      foreach ($uris as $i =&gt; $uri) {
          $loc = $dir . DIRECTORY_SEPARATOR . basename($uri);
          if ($overwrite &amp;&amp; file_exists($loc)) unlink($loc);
          $requests[] = new GuzzleHttp\Psr7\Request('GET', $uri, ['sink' =&gt; $loc]);
          echo "Downloading $uri to $loc" . PHP_EOL;
      }
      $pool = new \GuzzleHttp\Pool($client, $requests, [
          'concurrency' =&gt; 10,
          'fulfilled' =&gt; function (\Psr\Http\Message\ResponseInterface $response, $index) {
              // this is delivered each successful response
              echo 'success: '.$response-&gt;getStatusCode().PHP_EOL;
          },
          'rejected' =&gt; function ($reason, $index) {
              // this is delivered each failed request
              echo 'failed: '.$reason.PHP_EOL;
          },
      ]);
      $promise = $pool-&gt;promise();  // Start transfers and create a promise
      $promise-&gt;wait();   // Force the pool of requests to complete.
  }
  
  function downloadFilesAsync1(array $uris, string $dir, $overwrite=true) {
      $client = new \GuzzleHttp\Client();
      $promises = (function () use ($client, $uris, $dir, $overwrite) {
          foreach ($uris as $uri) {
              $loc = $dir . DIRECTORY_SEPARATOR . basename($uri);
              if ($overwrite &amp;&amp; file_exists($loc)) unlink($loc);
              yield $client-&gt;requestAsync('GET', $uri, ['sink' =&gt; $loc]);
              echo "Downloading $uri to $loc" . PHP_EOL;
          }
      })();
      (new \GuzzleHttp\Promise\EachPromise(
          $promises, [
          'concurrency' =&gt; 10,
          'fulfilled'   =&gt; function (\Psr\Http\Message\ResponseInterface $response) {
              //            echo "\t=&gt;\tDONE! status:" . $response-&gt;getStatusCode() . PHP_EOL;
          },
          'rejected'    =&gt; function ($reason, $index) {
              echo 'ERROR =&gt; ' . strtok($reason-&gt;getMessage(), "\n") . PHP_EOL;
          },
      ])
      )-&gt;promise()-&gt;wait();
  }
  </code></pre>