import csv import signal import time import threading import ping3 class Ping(threading.Thread): def __init__(self, ip: str): super().__init__() self._start: int = None self._end: int = None self._ping: int = None self.ip = ip def run(self) -> None: self._start = time.time_ns() / 1_000_000 self._ping = ping3.ping(self.ip, timeout=60, unit="ms") or -1 self._end = time.time_ns() / 1_000_000 def load(self) -> (int, int, int): self.join() return self._start, self._end, self._ping class PingRequester(threading.Thread): def __init__(self, ip: str, file: str): super().__init__() self.stop = False self.lock = threading.Lock() self.event = threading.Event() self.write_interval = 100 self.ip = ip self.list: [Ping] = [] self.file = open(file, 'a+') self.writer = csv.writer(self.file) def run(self) -> None: while not self.stop: threading.Thread(target=self._ping).start() time.sleep(1) data = [] for req in self.list: data.append(req.load()) self._write(data) def finish(self) -> None: self.stop = True def _ping(self) -> None: self.lock.acquire() request = Ping(self.ip) request.start() self.list.append(request) if len(self.list) >= self.write_interval and not self.event.is_set(): self.event.set() self.lock.release() data = [] for req in self.list[:self.write_interval]: data.append(req.load()) self.list = self.list[self.write_interval:] self._write(data) self.event.clear() else: self.lock.release() def _write(self, data: [(int, int, int)]) -> None: self.writer.writerows(data) self.file.flush() class BulkPing: def __init__(self, file: str, *ips: str): self.ips = ips self.event = threading.Event() self.write_interval = 100 self.list: [[Ping]] = [[] for _ in range(len(ips))] self.stop = False self.file = open(file, 'a+') self.writer = csv.writer(self.file) def start(self) -> None: while not self.stop: for i, ip in enumerate(self.ips): ping = Ping(ip) ping.start() self.list[i].append(ping) if not self.event.is_set() and all(len(pings) >= self.write_interval for pings in self.list): self.event.set() threading.Thread(target=self._write_cached_pings).start() time.sleep(1) def finish(self) -> None: self.stop = True def _write_cached_pings(self) -> None: rows = [] for i in range(self.write_interval): data = [] for pings in self.list: data.append(pings[i].load()[2]) rows.append(data) for i in range(len(self.list)): self.list[i] = self.list[i][self.write_interval:] self._write(rows) self.event.clear() def _write(self, rows: [[int]]): self.writer.writerows(rows) self.file.flush() def v1(): threads = [ PingRequester('1.1.1.1', 'data/1-1-1-1.csv'), PingRequester('217.237.148.22', 'data/217-237-148-22.csv'), PingRequester('192.168.2.1', 'data/192-168-2-1.csv') ] sig_received = False def stop(sig, frame): if sig_received: exit(1) print("Stopping threads gratefully (may take up to 60 seconds)") for thread in threads: thread.finish() signal.signal(signal.SIGINT, stop) for i, thread in enumerate(threads): thread.start() print(f'Started thread {i}') for thread in threads: thread.join() def v2(): ping = BulkPing('data/all.csv', '1.1.1.1', '217.237.148.22', '192.168.2.1') def stop(sig, frame): if ping.stop: exit(1) print("Stopping process gratefully (may take up to 60 seconds)") ping.finish() signal.signal(signal.SIGINT, stop) ping.start() if __name__ == '__main__': v2()