Language: EN

programacion-asincronia-concurrencia

What is asynchronous programming

Asynchronous programming is a set of techniques that allows applications to perform multiple tasks simultaneously, without blocking the main execution flow.

If your computer only did one thing, it wouldn’t be very useful. Imagine that every time you open a file, or visit a web page, your computer “freezes” until it finishes. It wouldn’t be very practical!

In fact, your computer does thousands of tasks “simultaneously”. It handles WiFi, paints the screen, reads the hard drive, runs a program, and reads the keyboard. It does all of that “more or less” at the same time.

programacion-asincronia-concurrencia

Your CPU, juggling processes

Similarly, you need to prepare your programs to do several things “at the same time”. That’s what we call asynchronous programming, creating programs that are capable of functioning in a non-fully sequential way.

Advantages of asynchrony

Why is it important to add asynchrony to your programs? Well, there are several reasons why you would want to add asynchrony to your programs.

The main reason to apply asynchrony in your programs is an improvement in user experience in the form of responsiveness. That is, in giving a response to the user.

Without asynchrony, your program couldn’t even put up a “loading” window with a spinning circle while loading data from somewhere. It would be blocked, and you couldn’t do anything at all.

The other major reason is that, in certain circumstances, it can result in an improvement in resource efficiency. Resources that are limited and can become a bottleneck.

For example, imagine that the processor itself is idle, waiting for a response from a website. With asynchrony, it is possible to take advantage of that wait to “insert” other calculations in between.

Difficulties of asynchronous programming

However, not everything was going to be advantages. Asynchronous programming has always been more difficult than sequential or synchronous programming. It always has been, and always will be.

This is simply because it is inherently more complex. It is always going to be more complicated to handle several things at once, than just one. Just like juggling with five balls… it’s harder than with one.

One of the problems is that you have to take into account temporal synchronization. Now, things don’t happen one after the other, they occur in parallel (or semi-parallel).

So, your mind must stop thinking of your program as a series of tasks that are executed sequentially, and start thinking of a schedule with several lines that can be parallel and non-deterministic.

Another big problem is access to shared resources. If a resource is being actively used by one process, another probably cannot use it. If both try to access it, you probably have an error.

Finally, you will also have difficulties in sharing memory. It is even possible for one process to be “doing its thing” and another process to modify a variable. Or that one task cannot access the memory of the other.

We didn’t have all these problems in synchronous programming. To manage these things, we have created a lot of tools and resources, such as mutexes, semaphores, monitors… but even so, you will always have added complexity to the design.

Mechanisms for asynchronous programming

In addition to the tools I have already mentioned, different programming languages have incorporated various mechanisms to make implementing asynchrony easier.

Some of them are:

  • Callbacks / Events: Functions that are passed as arguments to other functions and are executed after an operation is completed.
  • Promises / Futures: Objects that represent a value that may be available now, in the future, or never.
  • Async / Await: Syntax that allows writing asynchronous code in a way more similar to synchronous code.
  • Threads: Threads allow executing multiple tasks in parallel within the same process.
  • Co-routines: Functions that can pause their execution and yield control to other co-routines.
  • Event Loop: Mechanism that allows handling input/output operations in a non-blocking manner.

These mechanisms provide various ways to manage the execution of concurrent and asynchronous tasks, each with its own advantages and disadvantages.

Of course, the choice of the appropriate mechanism depends on the programming language and the type of application you are developing. We will delve into them in depth in the different articles of this chapter.