---
title: 'How to run HTTP requests in parallel in your PHP application'
source: 'https://youtube.com/watch?v=ZqgpglmtK5c'
video_id: 'ZqgpglmtK5c'
date: 2026-08-03
duration_sec: 599
---

# How to run HTTP requests in parallel in your PHP application

> Source: [How to run HTTP requests in parallel in your PHP application](https://youtube.com/watch?v=ZqgpglmtK5c)

## Summary

This video demonstrates how to execute multiple HTTP requests concurrently in a PHP application using the Symfony HTTP client. The presenter, Benjamin, explains the concept using an example from the Tideways codebase, showing how to reduce response times by parallelizing requests to storage servers.

### Key Points

- **PHP lacks built-in concurrency** [00:02] — PHP does not support multi-threading or concurrent code execution by default. Requests are handled separately by Apache or PHP-FPM, and there is no built-in way to run multiple SQL queries or render HTML parts in parallel within a single script.
- **Using curl for parallel requests** [01:01] — For a long time, the curl extension has allowed running HTTP requests in parallel. This can be used strategically to speed up applications by spreading expensive work to backend services or microservices.
- **Tideways profile network gateway** [01:43] — The example API fetches trace and call graph data from remote storage servers. These servers are a distributed SQLite system where each customer has databases, stored redundantly across multiple servers.
- **Parallel querying of storage servers** [03:01] — Instead of querying storage servers sequentially, they can be queried in parallel to ask if they have the trace payload. This reduces the time spent waiting for each server's response.
- **Symfony HTTP client makes concurrency simple** [04:46] — The Symfony HTTP client supports concurrent requests by default, requiring no special configuration. This is a key advantage for implementing parallel requests easily.
- **Blocking call issue** [06:12] — In the original code, calling getStatusCode() immediately blocks until the request completes, causing requests to run sequentially. This is why the requests were not concurrent.
- **Refactoring to gather responses first** [06:39] — The solution is to store all responses in an array first, then iterate over them to get status codes. This allows the requests to run concurrently.
- **Verifying concurrency in trace** [07:36] — After the refactor, the trace shows the HTTP calls running concurrently, with one completing early. This confirms the optimization works.
- **Scaling considerations** [08:35] — When parallelizing requests, the backend service must handle the increased load. For example, 100 concurrent users making 5 requests each means 500 concurrent requests to the backend.

### Conclusion

By using the Symfony HTTP client's built-in concurrency support, developers can easily parallelize HTTP requests in PHP, significantly reducing response times. This technique is simple to implement and can be applied to any application that makes multiple independent HTTP calls.

## Transcript

allows multi-threading or concurrent code execution by default. However, there is a simple trick that allows you to run at least some code concurrently in every application with the potential to reduce the response time
significantly. In this video, we are going to look at how to execute multiple HTTP requests concurrently using Symphony's HTTP client with an example right from our Tideways codebase. Mo, I'm Benjamin and my work uh is
focused on PHP performance topics for the last 10 years, helping thousands of developers, companies, and open-source projects along the way. PHP runs requests concurrently utilizing Apache or PHP FPM, but they are completely
separated from each other and they don't share state with each other. If you want to reduce the amount spent processing in a single script, then there's no built-in way to execute multiple SQL queries at the same time or render
different parts of the HTML output in multiple threads and then merging them. But for a long time, you can run HTTP requests in parallel using the curl extension. And if you do this strategically in your application, you
can get it faster as a result. For example, by spreading expensive work out to a backend service or to microservices, you can compute them in parallel. Before we get to the code, if you like to stay informed about PHP
performance topics, I would really like to see you subscribing to this channel or our newsletter. The link is in the description. We are going to look at an description. We are going to look at an API in our codebase that fetches uh data
API in our codebase that fetches uh data for traces and call graphs from a remote for traces and call graphs from a remote um storage server. Um the API is called um storage server. Um the API is called um profile network gateway and it um
finds binary data for a profile on this storage servers. The storage servers are um sort of a distributed SQLite system where every customer has SQLite
databases of traces and we store them in multiple servers for a redundancy and um for um when one of the servers goes down. So uh then when we query um the
data for one of the traces that you're looking at, we need to iterate over all of the storage servers and query them for this data. And uh sometimes one of
the storage servers doesn't have the trace because we don't store it on all trace because we don't store it on all of them uh only on a few of them. So uh this system is rather simple. You could probably have a much more clever
approach to do this, but um our performance constraints here are still performance constraints here are still very fine. So it um didn't um cause any problem to do this so far. What we can do, however, is if we have three storage
servers for example, we can um call out to them in parallel and ask them uh do you have this trace payload or not? and then um we can fetch them uh uh
concurrently at the same time and look which of the requests returned the result and then use that. So what do we have here? We iterate over the storage host IPs. Then using the Symfony HTTP client. We query um the
Symfony HTTP client. We query um the remote um storage for a response. We ask for the response code and then if we find something we return um sort of a value object of this data. Um so it's really binary. So we need to uh
uncompress it and JSON decode it. And then uh that's uh turns into this binary profile data type. So if we look at how this uh looks in um
sort of a trace displaying the events and how they occur, we can see um on our dev system which I'm working on here dev system which I'm working on here that we have the controller raw uh trace
data action being called and it it makes um three um three uh HTTP requests to this local API here which is this trace um storage server the they are not run in uh concurrency
they are uh run uh right next to each other or behind each other. So we can see the first one returns a 404 not found result the second one also and found result the second one also and then the third one returns a result. So
this here is really expensive um HTTP calls that if we run them concurrently we could avoid this uh hit in the code. So, how we do this with a Symfony HTTP client? And this is where I like the Symfony HTTP client actually because
it's so simple um to make APIs concurrent. Uh let's look at the documentation. There is a section about concurrent There is a section about concurrent requests. Here, Symphfony HTTP client
makes concurrent requests by default. This means you don't need to configure anything special to send multiple requests in parallel and process them efficiently. So um I believe Gazle is also the same. So I haven't looked at
also the same. So I haven't looked at Gazle for a while and doing this. Um Gazle has also an excellent API about um concurrent requests but we are using concurrent requests but we are using Symfony in our codebase. Um so the HTTP
client comes in handy. How does it work? So here we see um we iterate over a list So here we see um we iterate over a list of things and then we make a get request to an URL here and we store the responses and then we iterate through
the responses and read their content later. So um have looked at which doesn't run in parallel. So
going back we see we create the response but we immediately ask for the status but we immediately ask for the status code and this is a a blocking call in Symphony's HTTP client. So at that point it waits for the request to end and this
is why we see them running after each other. So let's rework this code a little bit. we introduce an array of responses
an array of responses and then we sort of duplicate this uh and then we sort of duplicate this uh for each um a little bit. So we store for each um a little bit. So we store the request and the responses here. Then
we iterate over the responses iterate over the responses and
then we query the status code here and do this work here. So instead of do this work here. So instead of we need to remove this block here. So we need to remove this block here. So first we gather all responses um um then
we iterate over them and ask the first one for the status code and this should one for the status code and this should make the request uh run uh concurrently. Let's see. So let's see how this looks in a trace um and if the concurrency is
now visible. We run the Chrome extension on this endpoint because this is the one that um has this parallel request. So it reloads
the page uh using a secret value and gathers the profiling data. We can select the raw trace data action from the list of uh resulting queries. Then
we can see here it looks a little bit different than before. We see one span here and this user interface a little bit funky with parallelism. But if we switch to the um call graph then we can see here that um we have the uh um HTTP
see here that um we have the uh um HTTP calls running concurrently and um one of them is completed and the request is ending early and um we've implemented a very simple performance optimization using the Symfony HTTP client and its
using the Symfony HTTP client and its way of um concurrently making HTTP the requests. As you can see, it is rather simple to use the Symfony HTTP client and also to use Gazle to implement this kind of um performance optimization in
your code. If you have a central user interface that a lot of users are using and there's a lot of performance spent in this single endpoint, then you can in this single endpoint, then you can think about how can I rework this to get
uh some or all of the data from a backend service, a second service I talk backend service, a second service I talk to and this one I call in parallel using my um uh HTTP client. Obviously, you need to scale out for this service. So
uh when one uh user request makes let's say five requests to this backend service then uh you need to have the scale available to do this. So if you scale available to do this. So if you have 100 concurrent users then this uh
backend service needs to handle 500 concurrent HTTP requests. So it's a question of um making the scale possible to uh reduce the response time of the application by a large amount of time. If you find this or other topics about
PHP performance interesting, I would really like to see you subscribe to this channel or to our newsletter. The link is in the description. Bye.
