如何使用多线程 ping 一系列 IP 地址

yuv*_*val 4 python multithreading multiprocessing

假设我有以下 IP 范围“10.0.0.x”。我需要在这个 ips 范围内循环 - “10.0.0.1-255”,ping 每个,并检查响应。

这是我的代码:

for ip in range(1, 256):
  fullIP = '10.0.0' + ip
  if(Ping(fullIP) == True):
    print(fullIP + ' responded')
  else:
    print(fullIP + ' did not respond')
Run Code Online (Sandbox Code Playgroud)

这段代码有效,但不幸的是它很慢。
我想通过多线程提高效率,所以我做了以下事情:

def PingRange(start, end):
  for ip in range(start, end):
  fullIP = '10.0.0' + ip
  if(Ping(fullIP) == True):
    print(fullIP + ' responded')
  else:
    print(fullIP + ' did not respond')

try:
  thread.start_new_thread( PingRange, (1, 123))
  thread.start_new_thread( PingRange, (123, 256))
except:
  print "Error: unable to start thread"
Run Code Online (Sandbox Code Playgroud)

这段代码也有效,但它可以更好地工作,更通用。
如果这段代码写得正确,那么我不会只是不断地创建两个线程;我会创建操作系统允许的尽可能多的线程。
有些计算机允许 8 个线程,有些计算机只允许 4 个,有些甚至不允许线程。

我怎样才能让这个程序在 Python 中使用最大数量的线程?

dan*_*ano 5

这个问题非常适合使用线程池。线程池以恒定数量的线程运行,获取工作项(函数或方法),并在其线程池中执行这些工作项。它具有内置队列,因此如果您将 100 个工作项分配给五个线程池,它将执行所有 100 个项目,但不会同时运行超过五个。

Python 中有两个内置线程池选项(取决于您使用的版本) -multiprocessing.dummy.Poolconcurrent.futures.ThreadPoolExecutor. ThreadPoolExecutor仅内置在 Python 3.x 中,但可从 PyPI 获得向后移植。multiprocessing.dummy.Pool在 2.6+ 中可用。使用 a multiprocessing.dummy.Pool,您的代码变得如此简单:

import multiprocessing.dummy

def ping_range(start, end):
    num_threads = # Number of threads to run in the pool.
    p = multiprocessing.dummy.Pool(num_threads)
    p.map(ping, [10.0.0.x for x in range(start,end)])

if __name__ == "__main__":
    PingRange(0, 255)
Run Code Online (Sandbox Code Playgroud)

下一个问题是用于num_threads. 我认为您对具有最大允许线程数的系统有一些误解。您可以Thread在任何系统上创建任意数量的对象,实际上没有什么可以阻止您,但是在某个时刻,您将创建如此多的线程,系统将无法处理它,性能将开始变得更糟,而不是更好。

CPU 密集型应用程序的经验法则(意味着它主要需要 CPU 来完成工作)是运行与 CPU 一样多的线程。然而,这个 ping 操作是 I/O 绑定的,这意味着大部分工作是将 ping 请求发送到外部系统,然后等待响应,这不需要 CPU 做任何事情。在这些情况下,通常可以使用超过 CPU 数量的数量。我们可以保守并使用2 * number_of_cpus,但您可以尝试使用更大的数字。

import multiprocessing
num_threads = 2 * multiprocessing.cpu_count()
Run Code Online (Sandbox Code Playgroud)

把它们放在一起:

import multiprocessing.dummy
import multiprocessing

def ping(ip):
   success = # Run the ping command here
   if success:
       print("{} responded".format(ip))
   else:
       print("{} did not respond".format(ip))
   return success

def ping_range(start, end):
    num_threads = 2 * multiprocessing.cpu_count()
    p = multiprocessing.dummy.Pool(num_threads)
    p.map(ping, [10.0.0.x for x in range(start,end)])

if __name__ == "__main__":
    ping_range(0, 255)
Run Code Online (Sandbox Code Playgroud)