Skip to content

Network Automation

My journey with Network & Cloud Automation

Menu
  • Beginner
  • DevOps-NetDevOps
  • Network Automation
    • Docker
    • Python Libraries
      • NAPALM
      • Netmiko
      • Jinja2
      • Scrapli
      • Yang
  • Cloud Automation
    • Terraform
  • Python 🐍 Tips and Tricks
Menu
multithreading with python for network engineers

Multithreading with Python for Network Engineers

Posted on August 12, 2021August 16, 2021 by Gurpreet Kochar

Up until now, we have been establishing connections to devices sequentially, i.e If you have 10 devices from which you want to pull show version data, the script will connect to device1, extract show version, goto device2, extra show version, connect to the device and extract show version and so on until all devices are done. You can imagine how slow this can get once you need to connect to hundreds/thousands of devices to fetch data and further amplified by if you need to get outputs of long-running commands from multiple devices. Let’s see how we can leverage the python threading module to connect multiple devices at once and achieve concurrency to reduce the overall execution time drastically.

MULTITHREADING WITH PYTHON

There are multiple ways to achieve parallel task execution. In this case, we want to connect to multiple devices at once and fetch data from devices instead of sequentially to save time.

import threading  # import python's threading module
from netmiko import ConnectHandler
import time
import logging


csr1000v1 = {
    'device_type': 'cisco_ios',
    'host':   'sandbox-iosxe-latest-1.cisco.com',
    'username': 'developer',
    'password': 'C1sco12345',
    'port' : 22,                # optional, defaults to 22
    'secret': 'C1sco12345',     # optional, defaults to ''
}
csr1000v2 = {
    'device_type': 'cisco_ios',
    'host':   'sandbox-iosxe-recomm-1.cisco.com',
    'username': 'developer',
    'password': 'C1sco12345',
    'port' : 22,
    'secret': 'C1sco12345',
}
iosxrv9000 = {
    'device_type': 'cisco_xr',
    'host':   'sandbox-iosxr-1.cisco.com',
    'username': 'admin',
    'password': 'C1sco12345',
    'port' : 22,
    'secret': 'C1sco12345',
}
nxosv9000 = {
    'device_type': 'cisco_nxos',
    'host':   'sandbox-nxos-1.cisco.com',
    'username': 'admin',
    'password': 'Admin_1234!',
    'port' : 22,
    'secret': 'Admin_1234!',
}


def connect_and_fetch(device_data):
    net_connect = ConnectHandler(**device_data)
    output = net_connect.send_command('show version', use_genie=True)
    print(net_connect.host)
    print("*" * len(net_connect.host))
    # print(output)


if __name__ == "__main__":
    threads = []
    all_devices = [csr1000v1, csr1000v2, iosxrv9000, nxosv9000]
    for device in all_devices:
        # Spawn threads and append to threads list
        th = threading.Thread(target=connect_and_fetch, args=(device,))
        threads.append(th)
    
    # iterate through threads list and start each thread to perform its task
    for thread in threads:
        thread.start()

    #Once all threads have done the work, join the output of all threads to return the final output.
    for thread in threads:
        thread.join()

Explanation:-

IMPROVEMENTS:-

The code above works fast sure but is it a good code, no, it is not. There are some loopholes here that we can fix and take care of especially when we are spawning multiple threads and can run into issues like

  1. We are spawning all threads ahead of time. So if you have hundreds of devices to connect to, you are essentially spawning those many threads before the threads even start to do something.
if __name__ == "__main__":
    threads = []
    all_devices = [csr1000v1, csr1000v2, iosxrv9000, nxosv9000]
    for device in all_devices:
        # Spawn threads and append to threads list
        th = threading.Thread(target=connect_and_fetch, args=(device,))
        threads.append(th)
        th.start()

    #Once all threads have done the work, join the output of all threads to return the final output.
    for thread in threads:
        thread.join()

2. The above doesn’t limit the number of threads you can spawn parallel. If you have a thousand devices, it will try to spawn 1000 threads and your application may crash if it’s unable to handle so many threads without proper error handling.

if __name__ == "__main__":
    max_threads = 50 # Set max threads to 50. You can see what number works best for you.
    threads = []
    all_devices = [csr1000v1, csr1000v2, iosxrv9000, nxosv9000]
    for device in all_devices:
        # Spawn threads and append to threads list
        th = threading.Thread(target=connect_and_fetch, args=(device,))
        threads.append(th)
        th.start()
        #After each thread is started and added to dictionary, we are checking if the total number
        #of threads is more than what we have configured. If yes, wait or else continue
        while True:
            alive_cnt = 0
            for t in self.threads:
                if t.is_alive():
                    alive_cnt += 1
            if alive_cnt >=max_threads:
                logging.info('Do not spawn new thread, already reached max limit of alive threads [%s]' % alive_cnt)
                time.sleep(2)
                continue
            break

    #Once all threads have done the work, join the output of all threads to return the final output.
    for thread in threads:
        thread.join()

3. Now that we have the basics right, there is a way to reduce the number of lines of manual coding that we had to do above and let python handle all this for you.

import concurrent.futures

if __name__ == "__main__":
    all_devices = [csr1000v1, csr1000v2, iosxrv9000, nxosv9000]
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
        executor.map(connect_and_fetch, all_devices)

Funny how python does all the work for you, it’s just about knowing where to find and how to get that done. In the above code, we are just telling python to set max_workers = 4 ( spawn 4 threads ) and execute the connect_and_fetch function on all the devices in all_devices list using the execute.map( ) method. Everything else is handled for you behind the scenes.

This is Multithreading with python for network engineers 101 for you. The next article in line will focus on MultiProcessing with Python for Network Engineers.

Keep in touch !!!

Enter your email address below to join my mailing list.

By clicking submit, you agree to share your email address with the site owner and Mailchimp to receive marketing, updates, and other emails from the site owner. Use the unsubscribe link in those emails to opt-out at any time.

Processing…
Success! You're on the list.
Whoops! There was an error and we couldn't process your subscription. Please reload the page and try again.

Know someone who may benefit? Share this:

  • Tweet
  • Click to share on Telegram (Opens in new window) Telegram
  • Click to share on WhatsApp (Opens in new window) WhatsApp
  • Click to email a link to a friend (Opens in new window) Email
  • More
  • Click to print (Opens in new window) Print
  • Click to share on Reddit (Opens in new window) Reddit
  • Share on Tumblr
  • Pocket

Like this:

Like Loading...

Related

4 thoughts on “Multithreading with Python for Network Engineers”

  1. Jack says:
    January 10, 2025 at 5:42 PM

    Dud. you are a good Engineer. Thank you

    Loading...
    Reply
  2. Pingback: Docker for Network Engineers Part III - Creating a custom docker image/container
  3. Pingback: Python Scrapli AsyncIO Usage – Network Automation
  4. Pingback: [Theory] Multithreading vs Multiprocessing vs AsyncIO –

Leave a Reply to JackCancel reply

All Blog Posts
My Resume

Upcoming Posts

Sorry - nothing planned yet!

Recent Posts

  • How to backup configuration to TFTP Server using Ansible – Part II
  • How to backup network devices using Ansible – Part I
  • Netmiko SSH Proxy/JumpServer
  • A short note on SASE
  • Understanding Ansible

Recent Comments

  1. Jack on Multithreading with Python for Network Engineers
  2. LifeCanvas on [Theory] Multithreading vs Multiprocessing vs AsyncIO
  3. Jasper Horng on Netmiko SSH Proxy/JumpServer
  4. asdfasdf on Python API Using FASTAPI – UPDATE – PUT – PATCH – Part V
  5. Gurpreet Kochar on Python Scrapli AsyncIO Usage

Archives

  • September 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
Topic Request / Suggestion
Loading
© 2025 Network Automation | Powered by Minimalist Blog WordPress Theme
%d