Asynchronous programming is on demand today. Especially in web-development where responsiveness of the application plays a huge role. No one wants to waste their time and to wait for a freezing application, while you are performing some database queries, sending an email or running some other potentially long-running tasks. Users want to receive responses to their actions, and they want these responses immediately. When your application becomes slow, you start losing your clients. Once a user has to deal with a freezing application, in most cases he or she simply closes it and never returns. When the UI freezes from the user’s point of view, it is not clear if your application is broken, or it is performing some long-running task and requires some time for it.
Modern applications tend to be responsive, but some potentially long-running tasks or blocking operations such as network and filesystem I/O or database queries can significantly slow down your application. To prevent an application from being blocked by these operations we can run them in background thus hiding the latency which they bring. So, an application stays responsive because it can continue with other work, for example, it can return the flow to UI or respond to other events.
Parallelism vs Asynchronous
Most people when they see asynchronous code immediately think “Oh, it’s cool! I can run my stuff in parallel!”. I may disappoint you but actually, it is not true, concurrency and parallelism is not the same thing. It is commonly misunderstood, so let’s try to understand why.
When running something asynchronously it means a non-blocking execution without waiting for completion. Instead, parallelism means running multiple separate tasks at the same time as independent units of work.
Do the task by yourself somewhere else and let me know when you are done and bring me the results. By this time I can continue to run my own task.
Asynchronous code requires handling dependencies between the order of execution and this is done via callbacks. When some job is done it notifies another job what it has done. Asynchronous code mostly deals with time (order of events).
Hire as many folks as you wish and split the task between them to complete this task quicker and notify me when you are done. I might continue to do my other stuff or if the task is urgent I will stay here and wait until you come back with the results. Then I can combine the results from these guys. Parallel execution often requires more resources so it mostly depends on hardware.
To illustrate the difference between asynchronous and parallel execution on real-world examples, we can compare two popular web servers: Apache and Nginx. They perfectly illustrate this difference: Nginx is asynchronous and event-based, while Apache uses parallel threads. Apache creates new threads for every additional connection, so there is a maximum number of allowable connections depending on the available memory in the system. When this limit of connections is reached Apache refuses additional connections. The limiting factor in tuning Apache is memory (remember that parallel execution often depends on hardware). If a thread stops, the client waits for the response until the thread becomes free and so it can send a response.
Nginx works differently than Apache and it doesn’t create new threads for each incoming request. It has a main worker process (or several workers, often a rule of thumb is to have one worker process for each CPU), which is single-threaded. This worker can handle thousands of concurrent connections. It does this asynchronously with one thread, rather than using multi-threaded parallel execution.
So, concurrency is a way to build things. It is a composition of independently executing things. Parallelism is a simultaneous execution of multiple things (they may be related and may not). In concurrency, we are dealing with a lot of different things at once. Parallelism is doing a lot of things at once. It looks like the same but these are actually different ideas. Concurrency is about structure, while parallelism is about execution.
Use can compare concurrency with I\O drivers in your OS (mouse, keyboard, display). They all are managed by the operating system, but each of them is an independent thing inside the kernel. These things are concurrent, they can be parallel but not necessary. They don’t need to run in parallel. So, to make concurrency work you have to create a communication between these independent parts to coordinate them.
Why Bother On Back-End?
setTimeout() function to demonstrate some asynchronous code:
When running this code we see the following:
setTimeout() function queues the code to run once the current call stack is done. This means that we break the synchronous code flow and delay some execution. The second
console.log() call is being executed before the queued one inside
But what about PHP? Well, out-of-box in PHP we don’t have nice and friendly tools to write really asynchronous code. There is no
Why Should I Use PHP, If We Have NodeJs and Go?
This sort of question is the most frequently asked when talking about asynchronous PHP. Somehow the community is often against using PHP as a tool for writing asynchronous code. Always someone suggests to simply use Go and NodeJs.
This tweet by assertchris perfectly describes it:
Basically how I feel about every "just use another language instead of async in PHP" post. pic.twitter.com/LnKXTIQodx— assertchris (@assertchris) 8 декабря 2017 г.
Yes, you can use Go or NodeJs to create asynchronous back-end applications, but it is not always the case. When you already have a solid background in PHP, it will be much easier for you just to dig in some libraries and tools for your use-case, instead of learning a new language and a new ecosystem. Such tools as ReactPHP or Amp allow you to write asynchronous code like you write it in NodeJS. These tools are mature enough and have stable versions, so you can safely use them in production.
Don’t be afraid to learn new language paradigm. PHP is much more than run the script, execute some code and die. You will be amazed to use your familiar PHP language in a completely new way, in the way you have never used it! Asynchronous code and event-driven programming will expand the way you think about PHP and how this language can be used. There is no need to learn a new language to write asynchronous applications just because someone blames PHP that it is not a right tool for it or because this is how I’ve always done it, it couldn’t possibly be improved on. Just give it a try!
This article is a part of the ReactPHP Series.