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

时间:2015-03-31 14:29:45

标签: 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')

此代码有效,但不幸的是它很慢 我想通过多线程提高效率,所以我做了以下几点:

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"

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

如何让这个程序使用Python中最大的线程数?

1 个答案:

答案 0 :(得分:4)

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

Python中有两个内置线程池选项(取决于您使用的版本) - multiprocessing.dummy.Poolconcurrent.futures.ThreadPoolExecutorThreadPoolExecutor仅在Python 3.x中内置,但PyPI提供了一个backport。 multiprocessing.dummy.Pool可在2.6+中使用。使用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)

下一个问题是num_threads的用途。对于拥有最大允许线程数的系统,我认为你略有错误信息。您可以在任何系统上创建任意数量的Thread个对象,并且实际上什么都不会阻止您,但在某个时刻您将创建如此多的线程,系统将无法处理它和性能将开始更糟,而不是更好。

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

import multiprocessing
num_threads = 2 * multiprocessing.cpu_count()

全部放在一起:

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)