Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Comment faire des pings avec asyncio ?

+1 vote

J’ai le code synchrone suivant:

from subprocess import run


def ping(hostname):
    result = run(["ping", "-c", "1 ", "-w100", hostname], capture_output=True)
    return result.returncode == 0


def main():
    hostnames = [
        "google.com",
        "qwant.com",
        "nimp",
    ]
    down = [hostname for hostname in hostnames if not ping(hostname)]
    return down


if __name__ == "__main__":
    down = main()
    assert down == ["nimp"]

Je souhaite le rendre asynchrone avec asyncio, voici ma tentative:

import asyncio
from subprocess import run


async def ping(hostname):
    cmd = f"ping -c1 -w100 {hostname}"
    result = await asyncio.create_subprocess_shell(cmd)
    return result.returncode == 0


async def main():
    hostnames = [
        "google.com",
        "qwant.com",
        "nimp",
    ]
    results = await asyncio.gather(*(ping(h) for h in hostnames))
    down = [hostname for hostname, result in zip(hostnames, results) if result]
    return down


if __name__ == "__main__":
    down = asyncio.run(main())
    assert down == ["nimp"]

Et le résultat:

/usr/local/lib/python3.7/asyncio/unix_events.py:861: RuntimeWarning: A loop is being detached from a child watcher with pending handlers
  RuntimeWarning)
Traceback (most recent call last):
  File "./async_ping.py", line 28, in <module>
    assert down == ["nimp"]
AssertionError

Le problème c’est que result.returncode est None.

demandé 16-Nov par Ryzz (208 points)

Je n'ai pas vraiment le temps d'y jeter un oeil, mais si tu veux t'inspirer de ce que j'avais fait, tu devrais pouvoir trouver une piste: http://www.tiger-222.fr/?d=2016/12/09/13/17/23-pinger-tout-un-reseau-version-sous-steroides

1 Réponse

+2 votes
 
Meilleure réponse

Premièrement, dans ma liste en intension de la version asynchrone, j’ai oublié le not.

Deuxièmement, il faut remplacer:

return result.returncode == 0

par:

return await result.wait() == 0

Enfin, pour éviter de polluer la sortie standard et la sortie d’erreur, il faut utiliser des PIPEs comme dans l’exemple de @Tiger-222:

from asyncio.subprocess import PIPE

async def ping(hostname):
    cmd = f"ping -c1 -w100 {hostname}"
    result = await asyncio.create_subprocess_shell(cmd, stdout=PIPE, stderr=PIPE)
    await result.communicate()
    return result.returncode == 0

Il est conseillé dans la doc d’utiliser la méthode communicate à la place de wait lorsqu’on utilise des PIPEs.

répondu 23-Nov par Ryzz (208 points)

Il y a aussi un exemple sur ce site :

https://hautefeuille.eu/post/python-async-thread/

Il y a 2 exemples, l'un avec l'utilisation du multithreading et l'autre avec asyncio.

...