需求:寫一個腳本,判斷192.168.11.0/24網絡裏,當前在線ip有哪些?python
知識點:shell
1 使用subprocess模塊,來調用系統命令,執行ping 192.168.11.xxx 命令網絡
2 調用系統命令執行ping命令的時候,會有返回值(ping的結果),須要用到stdout=fnull, stderr=fnull方法,屏蔽系統執行命令的返回值app
常規版本(代碼)異步
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()
執行效果:async
上面的執行速度很是慢,怎麼能讓程序執行速度快起來?ide
python提供了進程,線程,協程。分別用這三個對上面代碼改進,提升執行效率,測試一波效率測試
進程池異步執行 -- 開啓20個進程spa
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))
執行結果:
歡迎你們一塊兒來玩好PY,一塊兒交流。QQ羣:198447500