My last few weeks were busy writing some serious Async code in Python involving a lot of I/O involving two classes of devices next to each other.
- Ultra low-latency devices (e.g. Motor Drive signals)
- Super slow ones (e.g. USB Camera streams)
During the way, I have picked up a few interesting facts about the Async paradigm which I would like to share here with a simple analogy.
Asynchronous (or, simply Async) programming is a way of writing code that can be executed in multiple small tasks next-to-each-other. Now, these small tasks can “literally” run parallel to each other (or) at least, they can “create an impression” that they are running in parallel. These are two different possibilities with Async programming — Parallelism and Concurrency.
Parallelism is about simultaneous execution of tasks at a given time, in the form of threads or processes running next-to-each-other.
- Tasks execute literally in parallel to each other, most likely on different CPU cores.
- Very effective for CPU-bound operations (heavy-math tasks, stand-alone computations).
- Not suitable if you have to wait for data from other tasks which are running in parallel.
- multiprocessing module in Python is designed to achieve Parallelism.
Concurrency is about the simultaneous occurrence of tasks at a given time, in the form of co-routines. It merely gives you “an impression” that several tasks are running in parallel, but in reality, they are not.
- Tasks merely exist next to each other, switches between each other and uses single CPU core.
- Very effective for I/O-bound operations (UDP, USB, HTTP).
- Not suitable if you are controlling several I/O devices (usually, >2) as you will reach CPU contention quite quickly since it uses single CPU core.
- threading, asyncio modules in Python are designed to achieve Concurrency.
That’s all for now, more on Async patterns with example code for next time.
Till then, happy coding! 👨💻