我会首先尝试使用线程。您可以尝试创建一个线程池,其大小是您必须执行的 ping 总数,但最终我相信这不会比使用等于您拥有的 CPU 内核数的线程池大小更好(下面的解释) .以下是使用线程和多处理两种方式的比较:
ThreadPoolExecutor(255 个线程)
from concurrent.futures import ThreadPoolExecutor
import os
import platform
import subprocess
import time
def ping_ip(ip_address):
param = '-n' if platform.system().lower() == 'windows' else '-c'
try:
output = subprocess.check_output(f"ping {param} 1 {ip_address}", shell=True, universal_newlines=True)
if 'unreachable' in output:
return False
else:
return True
except Exception:
return False
def main():
t1 = time.time()
ip_addresses = ['192.168.1.154'] * 255
#with ThreadPoolExecutor(os.cpu_count())) as executor: # uses number of CPU cores
with ThreadPoolExecutor(len(ip_addresses)) as executor:
results = list(executor.map(ping_ip, ip_addresses))
#print(results)
print(time.time() - t1)
if __name__ == '__main__':
main()
打印:
2.049474000930786
您可以尝试使用 更少 个线程(ThreadPoolExecutor 构造函数的max_workers 参数)。见:concurrent.futures
我发现运行 8 个线程(这是我拥有的核心数量)的效果也差不多(时间:2.2745485305786133)。我相信这样做的原因是,尽管 ping 是一项与 I/O 相关的任务,但对子进程的调用必须在内部创建一个使用大量 CPU 的新进程,因此并发性在某种程度上受到处理器限制。
ProcessPoolExecutor(8 核)
from concurrent.futures import ProcessPoolExecutor
import os
import platform
import subprocess
import time
def ping_ip(ip_address):
param = '-n' if platform.system().lower() == 'windows' else '-c'
try:
output = subprocess.check_output(f"ping {param} 1 {ip_address}", shell=True, universal_newlines=True)
if 'unreachable' in output:
return False
else:
return True
except Exception:
return False
def main():
t1 = time.time()
ip_addresses = ['192.168.1.154'] * 255
with ProcessPoolExecutor() as executor:
results = list(executor.map(ping_ip, ip_addresses))
#print(results)
print(time.time() - t1)
if __name__ == '__main__':
main()
打印:
2.509838819503784
请注意,在我的 Linux 系统上,您必须是超级用户才能发出 ping 命令。