HLab

Julien Hautefeuille

Python multithreading et programmation asynchrone

L’objectif est de réaliser un ping vers un ensemble de machines d’un réseau local. Les deux exemples suivants utilisent d’un côté le multithreading et de l’autre la programmation asynchrone. Dans les deux cas, on utilise une file d’attente pour synchroniser les tâches.

Utilisation du multithreading

from threading import Thread
import subprocess
from queue import Queue

num_threads = 32
queue = Queue()
ips = ["127.0.0.1", "8.8.8.8", "192.168.0.23"]

def pinger(i, q):
    while True:
        ip = q.get()
        ret = subprocess.call("ping -w 1 -c 1 %s" % ip,
            shell=True,
            stdout=open('/dev/null', 'w'),
            stderr=subprocess.STDOUT)
        if ret == 0:
            print("%s ALIVE" % ip)
        else:
            print("%s DEAD" % ip)
        q.task_done()

for i in range(num_threads):
    worker = Thread(target=pinger, args=(i, queue))
    worker.setDaemon(True)
    worker.start()

for ip in ips:
    queue.put(ip)

queue.join()

Utilisation de la programmation asynchrone

import asyncio
import shlex
from functools import wraps

q = asyncio.Queue(maxsize=0)

ips = ["127.0.0.1", "8.8.8.8", "192.168.0.23"]

def ban_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("----8<-------------------------------------------------------")
        func(*args, **kwargs)
        print("----8<-------------------------------------------------------")
    return wrapper

@ban_decorator
def motd():
    print("\t Need a medic now !")

@asyncio.coroutine
def producer():
    for ip in ips:
        ping_cmd = "ping -w 1 -c 1 {}".format(ip)
        p = yield from asyncio.create_subprocess_exec(* shlex.split(ping_cmd),
            stdout=open('/dev/null', 'w'),
            stderr=asyncio.subprocess.STDOUT)
        print("Test IP : {}".format(ip))
        _outs, _err = yield from p.communicate()
        if p.returncode:
            yield from q.put("DEAD : %s" % ip)
        else:
            yield from q.put("LIVE : %s" % ip)

@asyncio.coroutine
def consumer():
    while not q.empty():
        elems = yield from q.get()
        print(elems)
    asyncio.get_event_loop().stop()

if __name__ == "__main__":
    motd()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(producer())
    loop.run_until_complete(consumer())
    loop.close()