Распараллелить вызовы функций в Python - PullRequest
0 голосов
/ 23 апреля 2020

с использованием python3 .6.9. Я хочу добиться следующего:

, имея список с клиентскими IP-адресами. Я хочу пропинговать каждого клиента в целях мониторинга. использование for-l oop приводит к проблеме, заключающейся в том, что до ее завершения требуется довольно много времени, особенно если некоторым пингам приходится ждать тайм-аут. поэтому я подумал о запуске каждого пинга в отдельной задаче.

как бы я это сделал? в настоящее время это выглядит так:

for i in vpnClients:
    response_list=pythonping.ping(vpnClients[i]['virtualAddress'], count=2)
    singleStat={ "measurement": "ping", "tags": { "virtual ip": vpnClients[i]['virtualAddress']}, "time": datetime.datetime.utcnow(), "fields": { "min": float(response_list.rtt_min_ms), "max": float(response_list.rtt_max_ms), "avg": float(response_list.rtt_avg_ms) }}
    json_body.append(singleStat)

, если вместо выполнения pythonping я бы хотел сделать асин c вызов функции (я мог бы обернуть это как:

 def doPing(ip):
    response_list=pythonping.ping(vpnClients[ip]['virtualAddress'], count=2)
    singleStat={ "measurement": "ping", "tags": { "virtual ip": vpnClients[ip]['virtualAddress']}, "time": datetime.datetime.utcnow(), "fields": { "min": float(response_list.rtt_min_ms), "max": float(response_list.rtt_max_ms), "avg": float(response_list.rtt_avg_ms) }}
    json_body.append(singleStat)


 for i in vpnClients:
    call_function(doPing(i))

это возможно?

thx, andre

1 Ответ

0 голосов
/ 24 апреля 2020

Проблема не так проста, как кажется. В идеале пакет pythonping предоставляет некоторый многоцелевой API, но это не так (в 2020 году в апреле). К сожалению, пакет pythonping также не является потокобезопасным, поэтому вы не можете go использовать пул потоков (и вы не можете использовать asyncio, как предлагается, потому что pythonping не поддерживает asyn c). Если вы выберете источник , вы увидите, что он просто проверяет пакеты ICMP и не может дифференцироваться по цели.

while time_left > 0:
        # Keep listening until a packet arrives
        raw_packet, source_socket, time_left = self.socket.receive(time_left)
        # If we actually received something
        if raw_packet != b'':
            response.unpack(raw_packet)
            # Ensure we have not unpacked the packet we sent (RHEL will also listen to outgoing packets)
            if response.id == packet_id and response.message_type !=  icmp.Types.EchoRequest.type_id:
return Response(Message('', response, source_socket[0]), timeout-time_left)

Если мы отправим 10 пакетов, первый ответ подтвердит все цели. Не круто.

То, что осталось, - это пул процессов. Если мы действительно хотим использовать asyn c api примерно так:

import datetime
import asyncio
import concurrent.futures
import pythonping

# python 3.6 we had had to do this:
loop = asyncio.get_event_loop()

vpnClients = [
        {'virtualAddress': '192.168.111.113'},
        {'virtualAddress': '192.168.111.1'},
        {'virtualAddress': '192.168.111.100'},
        ]


def myping(client):
    target = client['virtualAddress']
    res = pythonping.ping(target, count=2, timeout=2)
    return { "measurement": "ping", "tags": { "virtual ip": target}, "time": datetime.datetime.utcnow(), "fields": { "min": float(res.rtt_min_ms), "max": float(res.rtt_max_ms), "avg": float(res.rtt_avg_ms) }}


async def main():
    with concurrent.futures.ProcessPoolExecutor(max_workers=4) as pool:
        executors = [loop.run_in_executor(pool, myping, c) for c in vpnClients]
        result = await asyncio.gather(*executors)

    print(result)


# You could do this if you would have python 3.7
# asyncio.run(main())
# but for 3.6, we must:
loop.run_until_complete(main())

Мы должны использовать пользовательскую функцию myping, потому что функции-исполнители пула процессов должны возвращать выбираемые объекты отсюда ResponseList Pythonping не будет работать. Диктовка, которую вы используете, очень хороша (она может быть разборчивой).

Конечно, вы можете просто использовать многопроцессорный API.

Однако, если ваша сеть стабильна и быстра (виртуальные хосты?), Может быть лучше сократить время ожидания до чего-то небольшого.

 pythonping.ping(target, count=2, timeout=0.1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...