需求:写一个脚本,判断192.168.11.0/24网络里,当前在线ip有哪些?
知识点:
1 使用subprocess模块,来调用系统命令,执行ping 192.168.11.xxx 命令
2 调用系统命令执行ping命令的时候,会有返回值(ping的结果),需要用到stdout=fnull, stderr=fnull方法,屏蔽系统执行命令的返回值
常规版本(代码)
import os import time import subprocess def ping_call(): start_time = time.time() fnull = open(os.devnull, 'w') for i in range(1, 256): ipaddr = 'ping 192.168.11.' + str(i) result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull) current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime()) if result: print('时间:{} ip地址:{} ping fall'.format(current_time, ipaddr)) else: print('时间:{} ip地址:{} ping ok'.format(current_time, ipaddr)) print('程序耗时{:.2f}'.format(time.time() - start_time)) fnull.close() ping_call()
执行效果:
上面的执行速度非常慢,怎么能让程序执行速度快起来?
python提供了进程,线程,协程。分别用这三个对上面代码改进,提高执行效率,测试一波效率
进程池异步执行 -- 开启20个进程
import os import time import subprocess from multiprocessing import Pool def ping_call(num): fnull = open(os.devnull, 'w') ipaddr = 'ping 192.168.11.' + str(num) result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull) current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime()) if result: print('时间:{} ip地址:{} ping fall'.format(current_time, ipaddr)) else: print('时间:{} ip地址:{} ping ok'.format(current_time, ipaddr)) fnull.close() if __name__ == '__main__': start_time = time.time() p = Pool(20) res_l = [] for i in range(1, 256): res = p.apply_async(ping_call, args=(i,)) res_l.append(res) for res in res_l: res.get() print('程序耗时{:.2f}'.format(time.time() - start_time))
执行结果:
线程池异步执行 -- 开启20个线程
import os import time import subprocess from concurrent.futures import ThreadPoolExecutor def ping_call(num): fnull = open(os.devnull, 'w') ipaddr = 'ping 192.168.11.' + str(num) result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull) current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime()) if result: print('时间:{} ip地址:{} ping fall'.format(current_time, ipaddr)) else: print('时间:{} ip地址:{} ping ok'.format(current_time, ipaddr)) fnull.close() if __name__ == '__main__': start_time = time.time() thread_pool = ThreadPoolExecutor(20) ret_lst = [] for i in range(1, 256): ret = thread_pool.submit(ping_call, i) ret_lst.append(ret) thread_pool.shutdown() for ret in ret_lst: ret.result() print('线程池(20)异步-->耗时{:.2f}'.format(time.time() - start_time))
执行结果:
协程执行---(执行多个任务,遇到I/O操作就切换)
使用gevent前,需要pip install gevent
from gevent import monkey;monkey.patch_all() import gevent import os import time import subprocess def ping_call(num): fnull = open(os.devnull, 'w') ipaddr = 'ping 192.168.11.' + str(num) result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull) current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime()) if result: print('时间:{} ip地址:{} ping fall'.format(current_time, ipaddr)) else: print('时间:{} ip地址:{} ping ok'.format(current_time, ipaddr)) fnull.close() def asynchronous(): # 异步 g_l = [gevent.spawn(ping_call, i) for i in range(1, 256)] gevent.joinall(g_l) if __name__ == '__main__': start_time = time.time() asynchronous() print('协程执行-->耗时{:.2f}'.format(time.time() - start_time))
执行结果:
遇到I/O操作,协程的效率比进程,线程高很多!
总结:python中,涉及到I/O阻塞的程序中,使用协程的效率最高
最后附带协程池代码
gevent.pool
from gevent import monkey;monkey.patch_all() import gevent import os import time import subprocess import gevent.pool def ping_call(num): fnull = open(os.devnull, 'w') ipaddr = 'ping 192.168.11.' + str(num) result = subprocess.call(ipaddr + ' -n 2', shell=True, stdout=fnull, stderr=fnull) current_time = time.strftime('%Y%m%d-%H:%M:%S', time.localtime()) if result: print('时间:{} ip地址:{} ping fall'.format(current_time, ipaddr)) else: print('时间:{} ip地址:{} ping ok'.format(current_time, ipaddr)) fnull.close() if __name__ == '__main__': start_time = time.time() res_l = [] p = gevent.pool.Pool(100) for i in range(1, 256): res_l.append(p.spawn(ping_call, i)) gevent.joinall(res_l) print('协程池执行-->耗时{:.2f}'.format(time.time() - start_time))
执行结果:
原文地址:http://blog.51cto.com/haowen/2119954