运维少年系列 python and cisco (4)
骚年 运维少年
运维少年系列 python and cisco (4)
说明
本章使用了多线程的方式提高脚本执行的效率,本章也是本系列文章的最后一个内容。回顾前三章,从单台交换机到多台交换机然后到异常处理,到今天的多线程,我觉得还算比较连贯吧~
多线程
为什么要使用多线程?在前面我们写的所有程序都是单线程的,串行执行,也就是说,要等上一个命令执行完成之后,下一个命令才能执行,但很显然,在机器比较多的情况下显得效率很低。所以我们应该使用多线程,使程序并发执行。
单线程和多线程比较
- 单线程执行时间
来看看上一次写的脚本的执行时间吧(动图)~
可以看到,需要28s,这仅仅是三台机器啊~如果100台呢,那也太久了吧~
- 多线程执行时间
来看看多线程的执行时间是多少吧(动图)~
可以看到,使用了多线程之后,速度提升了很多~
多线程使用
多线程的简单使用
python中的多线程实现使用的是threading函数,但是在使用多线程的时候,可能会遇到很多问题。先来看看多线程简单的用法吧
import threading # 导入多线程模块
import time
def run(num): # 定义函数(必须)
print 'this is the thread ', num
time.sleep(1)
for i in range(20):
t = threading.Thread(target=run,args=(i,)) # 实例化,target表示需要使用多线程的函数名,args为传入的参数,必须为元组,所以如果只有一个参数,需要加,号
t.start() #运行
多线程需要考虑的问题
在使用多线程的时候,线程之间会抢占资源,不按顺序执行,比如:在连接主机的时候,我们希望从连接到连接成功之前,目标IP保持不变,很显然,如果连接的时候目标IP发生变化,会导致连接出错或者验证失败。比如
import paramiko
import socket
import time
import threading
starttime = time.time()
user = 'yunwsn'
passwd = '123456'
s = paramiko.SSHClient()
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
IP = file('IP.txt','rb')
def run(ip): # 定义函数
try:
s.connect(ip,username=user,password=passwd,timeout=5,look_for_keys=False,allow_agent=False)
print '[ \033[0;32m success\033[0m ] login %s ' %ip
cmd = s.invoke_shell()
command = file('command.txt','rb')
for command in command.xreadlines():
cmd.send(command)
time.sleep(0.3)
output = cmd.recv(65535)
print output
cmd.close()
except paramiko.ssh_exception.NoValidConnectionsError:
print '[ \033[0;31m failed \033[0m ] Unable to connect to %s ' % ip
except socket.error,err:
print '[ \033[0;31m failed \033[0m ] %s to %s' %(err,ip)
except paramiko.ssh_exception.AuthenticationException:
print '[ \033[0;31m failed \033[0m ] Authentication failed on %s' % ip
for i in IP.xreadlines(): # 循环IOP
t = threading.Thread(target=run, args=(i,)) # 多线程实例化
t.start() # 启用多线程
IP.close()
执行效果如下:
[root@yunwei cisco]# python ywsn_p_c_lab4.py
[ failed ] Authentication failed on 192.168.108.252
[ failed ] Authentication failed on 192.168.108.253
[ failed ] Authentication failed on 192.168.108.251
[root@yunwei cisco]#
这时候我们就需要用到RLock办法了,RLock可以在指定的范围内锁定值,保证这个值使不会被修改。很明显在我们这个程序用,我们要在s.connect(ip,username=user,password=passwd,timeout=5,look_for_keys=False,allow_agent=False)这里进行数据锁定,直到它连接成功。
- 如何锁定数据
那怎么锁定呢?这需要使用到RLock办法,具体使用如下:
lock = threading.RLock() # 实例化
lock.acquire() # 开始锁定
lock.release() # 解锁
我们只需要在开始锁定和解锁之间加上程序需要锁定值的代码即可
def run(ip):
try:
lock.acquire()
s.connect(ip,username=user,password=passwd,timeout=5,look_for_keys=False,allow_agent=False)
lock.release()
print '[ \033[0;32m success\033[0m ] login %s ' %ip
对于命令来说也是一样的,在执行命令的时候,需要锁定该值,不然会出现以下情况:
Sw2(config)#
name V80
Sw1(config-vlan)#
vlan 100
Sw3(config-vlan)#
int e0/1
Sw2(config-if)#
vlan 90
Sw1(config-vlan)#
name V100
Sw3(config-vlan)#
switchport mode access
Sw2(config-if)#
name V90
Sw1(config-vlan)#
exit
Sw3(config)#
switchport trunk encapsulation dot1q
数据全部乱了…
实现代码
import paramiko
import socket
import time
import threading
user = 'yunwsn'
passwd = '123456'
s = paramiko.SSHClient()
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
IP = file('IP.txt','rb')
lock = threading.RLock()
def run(ip):
try:
lock.acquire()
s.connect(ip,username=user,password=passwd,timeout=5,look_for_keys=False,allow_agent=False)
lock.release()
print '[ \033[0;32m success\033[0m ] login %s ' %ip
cmd = s.invoke_shell()
command = file('command.txt','rb')
for command in command.xreadlines():
lock.acquire()
cmd.send(command)
lock.release()
time.sleep(0.3)
output = cmd.recv(65535)
print output
cmd.close()
except paramiko.ssh_exception.NoValidConnectionsError:
print '[ \033[0;31m failed \033[0m ] Unable to connect to %s ' % ip
except socket.error,err:
print '[ \033[0;31m failed \033[0m ] %s to %s' %(err,ip)
except paramiko.ssh_exception.AuthenticationException:
print '[ \033[0;31m failed \033[0m ] Authentication failed on %s' % ip
for i in IP.xreadlines():
t = threading.Thread(target=run, args=(i,))
t.start()
IP.close()
- 效果(动图)