Wednesday, 1 October 2014

A synchronous explanation of concurrency

Relatively new on the PHP scene are the following words:
  • Concurrent
  • Parallel
  • Asynchronous
These words have very specific meanings, they are not interchangeable.

It's important to communicate our ideas precisely, so that we don't confuse our audience. We should not try to make what we are saying more complex than it is, quite the opposite; it is in our best interest to make our ideas as palatable as possible.

I intend to provide a coherent, correct, explanation of what concurrency in programming is all about.

I'm going to use the example of a program which has three distinct tasks to execute, what the tasks are is unimportant for the explanation.

Synchronous Execution

The following diagram shows our program's execution:
 ---      ||
| 0 |     ||
| 0 |     ||
| 0 |     ||
| 0 |     ||
| 0 |     ||
| 0 |    \  /
|---|     ||
| 1 |     ||
| 1 |     ||
| 1 |    Time
| 1 |     ||
| 1 |     ||
| 1 |     ||
|---|     ||
| 2 |    \  /
| 2 |     ||
| 2 |     ||
| 2 |     ||
| 2 |     ||
| 2 |     ||
 ---      ||
We can see that the instructions for each task are executed in a linear fashion, by a single thread of execution.

Parallel Concurrency

For execution of our tasks to be parallel requires more than one thread of execution:
 -----------      ||
| 0 | 1 | 2 |     ||
| 0 | 1 | 2 |     ||
| 0 | 1 | 2 |     ||
| 0 | 1 | 2 |    \  /
| 0 | 1 | 2 |     ||
| 0 | 1 | 2 |     ||
 --- -------      ||
We can see from the diagram that our tasks run truly concurrently, concurrently with respect to time, reducing the overall time it takes to execute all three tasks.

Asynchronous Concurrency

The following diagram shows the asynchronous model:
 ---      ||
| 2 |     ||
| 1 |     ||
| 0 |     ||
| 1 |     ||
| 0 |     ||
| 1 |    \  /
|---|     ||
| 1 |     ||
| 2 |     ||
| 1 |    Time
| 0 |     ||
| 1 |     ||
| 2 |     ||
|---|     ||
| 0 |    \  /
| 0 |     ||
| 2 |     ||
| 2 |     ||
| 2 |     ||
| 0 |     ||
 ---      ||
We can see that the tasks are interleaved by the programmer, forcing the tasks to execute concurrently with respect to each other, but it seems to take as long as the synchronous model to execute.

Why write asynchronous code ?

Asynchronous concurrency is most useful when our tasks are I/O bound, where a considerable amount of time is actually spent waiting.

The following diagram shows the synchronous execution of our I/O bound tasks:
 ---      ||
| 0 |     ||
| 0 |     ||
| - |     ||
| - |     ||
| 0 |     ||
| 0 |    \  /
|---|     ||
| 1 |     ||
| 1 |     ||
| - |    Time
| - |     ||
| 1 |     ||
| 1 |     ||
|---|     ||
| 2 |    \  /
| 2 |     ||
| - |     ||
| - |     ||
| 2 |     ||
| 2 |     ||
 ---      ||
We can see that there is time spent doing literally nothing while waiting for subsystems and or hardware to do their job !

The asynchronous model has our instructions interleaved allowing us to eliminate waiting and continue executing another tasks instructions, making the diagram for asynchronous I/O bound code look more like:
 ---      ||
| 2 |     ||
| 0 |     ||
| 1 |     ||
| 0 |    \  /
|---|     ||
| 2 |     ||
| 1 |    Time
| 0 |     ||
| 2 |     ||
|---|     ||
| 1 |    \  /
| 1 |     ||
| 2 |     ||
| 0 |     ||
 ---      ||
So asynchronous concurrency can also reduce the time it takes to execute the same I/O bound instructions by executing another tasks instructions.

Why write parallel code ? 

Asynchronous concurrency can only help in the case of I/O bound code, parallel concurrency has a much bigger domain (the rest).

Just like asynchronous concurrency however there are limits; it is a mistake to think that throwing threads at anything will make it faster.

Achieving parallel concurrency is a huge subject, far too big for the footnote of my first blog post; I intend to cover the subject in detail.

No comments:

Post a Comment