Concurrence

Table of contents

Summarise with:

Concurrence refers to the a system’s ability to perform multiple tasks simultaneously. Concomitance is therefore an essential feature that enables developers to create applications capable of performing several operations simultaneously, thereby improving the software’s performance and efficiency. 

Concurrency can be achieved by using various execution threads, which are independent processing units which can execute tasks concurrently. Programming languages provide various ways of working with threads, enabling developers to implement concurrency effectively in their applications. 

An example of concurrency and threads

One of the most common ways of working with concurrency – using Python as an example – is by using the `Thread` class or implementing the `Runnable` interface. For example, you can create a class that extends the `Thread` class and override the `run()` method to define the task to be executed in a separate thread. Basic example: 

import threading 

 

# Define a function to be executed by a thread 

def task(): 

    print(«Hello from the thread») 

 

# Create a thread and execute the task function 

thread = threading.Thread(target=task) 

thread.start() 

 

In this example, a function called `tarea()` is defined which simply prints a message to the console. A `Thread` object is then created by specifying the `tarea` function as the thread’s target, and the thread is started by calling the `start()` method. 

Concurrency with ThreadPoolExecutor

In addition to the threading module, Python also provides the concurrent.futures module, which offers a high-level interface for working with concurrency and parallelism. This module includes classes such as ThreadPoolExecutor and ProcessPoolExecutor, which allow functions to be executed concurrently using pools of threads or processes. Here is an example of how to use `ThreadPoolExecutor`: 

 

from concurrent.futures import ThreadPoolExecutor 

 

# Define a function to be executed by a thread 

def task(): 

    print(«Hello from the thread») 

 

# Create a ThreadPoolExecutor with a pool of 5 threads 

executor = ThreadPoolExecutor(max_workers=5) 

 

# Running multiple tasks using the ThreadPoolExecutor 

for _ in range(10): 

    executor.submit(task) 

 

# Shut down the ThreadPoolExecutor once all tasks have been completed 

executor.shutdown() 

In this example, a ThreadPoolExecutor is created with a maximum of 5 threads in the pool. The submit() method is then used to submit tasks to be executed by the thread pool. Once all the tasks have been submitted, the shutdown() method is called to shut down the ThreadPoolExecutor. 

Now, if we had to make multiple requests to different websites and process the data, we can use a “ThreadPoolExecutor” to send the requests in parallel and then process the results concurrently. 

from concurrent.futures import ThreadPoolExecutor 

import requests 

 

# Function for making an HTTP request 

def make_request(url): 

    response = requests.get(url) 

    return response.text 

 

urls = [‘https://sitio1.com’, ‘https://sitio2.com’, ‘https://sitio3.com’] 

 

# Create a ThreadPoolExecutor 

with ThreadPoolExecutor() as executor: 

    # Send requests in parallel 

    results = executor.map(make_request, urls) 

 

# Process the results 

for result in results: 

    process(result) 

Generally speaking, concurrency enables developers to create faster and more efficient applications by making effective use of system resources. This can be achieved by using the threading module to work with threads, although this does add an extra layer of complexity to the system’s programming. 

Share in:

Related articles

Systems modelling

Systems modelling: what it is, characteristics and types

The real world can be explained using a simulator or through representative models. Even though the components of real-world systems are far more complex, system modelling enables us to familiarise ourselves with their processes. Therefore, to understand

Metaheuristics

Metaheuristics are a set of techniques and algorithms designed to solve complex optimisation problems that cannot be efficiently tackled by exact methods. These problems are often large-scale, non-linear and multivariate problems, which makes

Data migration best practices

Data migration: types and best practices Data migration is a crucial process for businesses in the digital age that involves more than just moving information, it also involves updating and optimising systems and formats.

Scroll to Top