百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

网络工程师的Python之路——netdev(异步并行)

off999 2024-10-18 08:07 69 浏览 0 评论

弈心:从事计算机网络工作11年(新加坡7年,沙特4年),2013年考取CCIE,在新加坡先后任职于AT&T,新加坡交通部,苹果,Equinix,苏格兰皇家银行等大型企业、银行和政府部门。 目前供职于“世界第一土豪大学“沙特阿卜杜拉国王科技大学(KAUST),担任Senior Network Engineer,为KAUST校史上第一位也是唯一一位华人IT部门高级职员。2019年6月在知乎发布了华语圈第一本专门为编程零基础的网络工程师量身打造的Python教程《网络工程师的Python之路》。


对网工来说,我们通常必须借助paramiko,netmiko,NAPALM或者pyntc等这些第三方开源模块才能通过SSH或者各种API来登录、操作、管理各种网络设备。很遗憾的是,由于异步在Python中引入较晚(Python 3.4过后才支持异步),上述所有这些模块都不支持异步。也就意味着在不使用多线程的情况下,运行Python脚本的主机必须一台一台地登录设备执行代码。假设登录一台交换机执行配置需耗时5秒的话,那么在拥有1000台交换机的大型企业网里就要耗时5000秒才能执行完脚本,效率太低。

2019年4月,受netmiko项目的启发,俄罗斯网络运维开发工程师Sergey Yakovlev在netmiko的基础上开发了一个叫做netdev的开源模块,该模块依赖于netmiko,并且需要至少Python3.5以上才能运行,最大的特点是支持对网络设备进行异步登录和操作。

在讲解netdev的用法前,首先我们需要知道什么是“同步”(Synchronous),什么是“异步”(Asynchronous),以及为什么使用异步能够帮助我们提升我们创建的Python脚本的工作效率。


1. 同步vs异步

所谓同步,可以理解为每当系统执行完一段代码或者函数后,系统将一直等待该段代码或函数返回的值或消息,直到系统接收到返回的值或消息后才继续往下执行下一段代码或者函数,在等待返回值或消息的期间,程序处于阻塞状态,系统将不做任何事情

本文前面所有涉及到管理多个设备的实验中,我们都是将设备的IP地址预先写入一个名为“ip_list.txt”的文本文件,然后在脚本里使用open()函数将其打开,然后调用readlines()函数并配合for循环读取每个设备的IP地址,然后通过paramiko或者netmiko一台设备接一台地完成SSH登录。像这样Python一次只能登录一台设备,只有在完成一台设备的配置后才能继续登录下一台设备继续配置的方式就是一种典型的“同步”。

而异步则恰恰相反,系统在执行完一段代码或者函数后,不用阻塞性地等待返回的值或消息,而是继续执行下一段代码或函数,在同一时间段里执行多个任务(而不是傻傻的等着一件事情做完并且直到结果出来了以后才去做下件事情),将多个任务并行,从而提高程序的执行效率。如果你有读过数学家华罗庚的《统筹方法》,一定不会对其中所举的例子感到陌生:同样是沏茶的步骤,因为烧水需要一段时间,你不用等水煮沸了过后才来洗茶杯、倒茶叶(类似“同步”),而是在等待烧水的过程中就把茶杯洗好,把茶叶倒好,等水烧开了就能直接泡茶喝了,这里烧水、洗茶杯、倒茶叶三个任务是在同一个时间段内并行完成的,这就是一种典型的“异步”。


2. 单线程vs多线程

过去的Python并不支持异步,因为不管是同步还是异步,它们都是在单线程下完成的。而之前在Python中已经有了多线程(Multithreading)的存在,程序可以启动多个线程同时完成多个任务,如果一个线程阻塞,其他线程并不受影响,程序并不会卡死。后来Python在3.4.x版本中开始加入了异步,为什么要加入呢?因为多线程虽然效率很高,但是程序在切换线程的时候会占用系统资源,产生额外的开销。另外因为异步只用了一个线程,不用担心多线程复杂的锁机制(Lock Mechanism),这也是异步被加入进Python的原因之一。关于多线程及其锁机制的话题超出了本文的讨论范围,读者可以自己参阅其他的材料深入学习。


3. 异步在Python中的应用

自从Python在3.4.x版本起开始支持异步后,关于异步的Python语法几经更改,在Python3.4、Python3.5、Python3.7中异步的实现方式有很大的不同,本文后面的例子中都将基于Python 3.8.2来讲解异步的使用。

要了解异步在Python中的应用,必须知道什么是协程(Corountine),什么是任务(Task),什么是可等待对象(Awaitable Object)

协程可以理解为线程的优化,我们可以把协程看成一种微线程。它是一种比线程更节省资源、效率更高的系统调度机制。而异步就是基于协程实现的。在Python中实现协程的模块主要有asyncio,gevent和tornado,使用较多的是asyncio。首先来看下面的例子:

 #coding=utf-8
 import asyncio
 import time
  
 async def main():
  print('hello')
  await asyncio.sleep(1)
  print('world')
  
 print (f"程序于 {time.strftime('%X')} 开始执行")
 asyncio.run(main())
 print (f"程序于 {time.strftime('%X')} 执行结束")  
  • 在Python中,我们通过在def语句前加上async语句来将一个函数定义为协程函数,在上面的例子中,main()现在被定义为了协程函数
  • 这里的“await asyncio.sleep(1)”表示临时中断当前的函数一秒钟,如果程序里还有其他函数的话,继续执行下一个函数,直到下一个函数执行完毕后,再返回来执行这个main()程序,因为这里我们除了一个main()函数之外没有其他的函数了,所以在print('hello')后,main()函数休眠了1秒钟,然后继续print(‘world’)。
  • 协程函数不是普通的函数,这里我们不能直接用“main()”来调用它,我们需要使用“asyncio.run(main())”才能执行该协程函数。
  • 这里我们配合time模块的strftime()函数来记录程序开始前的时间和程序结束后的时间,可以看到总共耗时确实是1秒钟。

这里需要注意的是不要把 “await asyncio.sleep(1)”和“time.sleep(1)”弄混,后者是在“同步”中使用的休眠操作,前者是在“异步”中使用的,因为这里我们只有main()一个函数需要执行,所以你暂时感受不到这两者有什么区别,不用着急,继续来看下面的两个例子你就知道了:

 #coding=utf-8
 import asyncio
 import time
  
 async def say_after(what, delay):
   print(what)
  await asyncio.sleep(delay)
  
 async def main():
  print (f"程序于 {time.strftime('%X')} 执行结束")
  await say_after('hello',1)
  await say_after('world',2)
  print (f"程序于 {time.strftime('%X')} 执行结束")
  
 asyncio.run(main())
  • 这里我们在协程函数main()的基础上加入了另外一个函数say_after(),同样的,我们用async将它定义为了协程函数。
  • 我们在main()函数中两次调用say_after()函数,因为say_after()是一个协程函数,因此在调用它时,前面必须加上await。
  • 当main()第一次调用say_after()函数时,我们首先打印出hello,然后休眠1秒,第二次调用say_after()函数时,我们打印出world,然后再休眠两秒,两次调用完毕后总共花费了3秒钟来运行完整个程序, 如下:

这里你会说,第一次花了1秒,第二次花了2秒,总共3秒时间,这没节省时间啊,两此调用的say_after()函数并没有并行啊,这和同步有什么区别?别急,继续往下看:

 #coding=utf-8
 import asyncio
 import time
  
 async def say_after(what, delay):
  await asyncio.sleep(delay)
  print(what)
  
 async def main():
 task1 = asyncio.create_task(say_after('hello',1))
  task2 = asyncio.create_task(say_after('world',2))
  print (f"程序于 {time.strftime('%X')} 开始执行")
  await task1
  await task2
  print (f"程序于 {time.strftime('%X')} 执行结束")
  
 asyncio.run(main())
  • 要实现异步并行,需要将协程函数打包成一个任务(Task),这里我们使用asyncio的create_task()函数将say_after()打包了两次,并分别赋值给task1和task2两个变量。然后使用await来调用task1和task2两个任务。
  • 运行脚本后可以看到,因为task1和task2是并行执行的,所以程序总共只耗时两秒钟即告完成(06:57:04到06:57:06)!

最后来说说什么是可等待对象(Awaitable Object),可等待对象的定义很简单:如果一个对象可以在await 语句中使用,那么它就是可等待对象。可等待对象主要有三种类型:协程、任务以及Future。协程和任务前面已经讲到了,Future不在本文的讨论范围内,读者可以自己参阅其他的材料深入学习。

4. netdev的安装和应用

截至2020年5月,netdev支持7家厂商的12种操作系统:

  • Cisco IOS
  • Cisco IOS XE
  • Cisco IOS XR
  • Cisco ASA
  • Cisco NX-OS
  • HP Comware (like V1910 too)
  • Fujitsu Blade Switches
  • Mikrotik RouterOS
  • Arista EOS
  • Juniper JunOS
  • Aruba AOS 6.X
  • Aruba AOS 8.X
  • Terminal

Netdev可以通过pip直接下载安装(因为netdev依赖于netmiko,下载netdev前请确认你的Python主机已经安装了netmiko):

下载完成后进入Python编辑器,如果import netdev没有报错则说明安装成功:

在使用netdev进行异步操作之前,我们先来做个“同步”和“异步”的对比试验,首先我们用传统的“同步”方式,通过netmiko对5台交换机(192.168.2.11--192.168.2.15)下的“line vty 5 15”配置“login local”,并统计从脚本开始运行到脚本执行完成所耗费的时间,然后我们再使用netdev,通过“异步”的方式对同样的5台交换机做同样的配置,并计时,最后将两次耗时相比较,看看孰优孰劣。

传统的“同步”方案的脚本如下(交换机192.168.2.11 – 192.168.2.15的IP的地址被保存在一个名叫ip_list.txt的文件里):

 from netmiko import ConnectHandler
 import time
  
 f = open('ip_list.txt')
 start_time = time.time()
  
 for ips in f.readlines():
  ip = ips.strip()
  SW = {
   'device_type': 'cisco_ios',
   'ip': ip,
   'username': 'python',
   'password': '123',
  }
  connect = ConnectHandler(**SW)
  print ("Sucessfully connected to " + SW['ip'])
  config_commands = ['line vty 5 15','login local','exit']
  output = connect.send_config_set(config_commands)
  print (output)
  
 print ('Time elapsed: %.2f'%(time.time()-start_time))

执行脚本看效果:

可以看到,通过“同步”方式一台一台登录5台交换机完成配置总共耗时了45.02秒。

接下来我们再来看netdev的表现,代码如下:

 import asyncio
 import netdev
 import time
  
 async def task(dev):
  async with netdev.create(**dev) as ios:
  commands = ["line vty 5 15", "login local","exit"]
  out = await ios.send_config_set(commands)
  print(out)
  
 async def run():
  devices = []
  f = open('ip_list.txt')
  for ips in f.readlines():
  ip = ips.strip()
  dev = { 'username' : 'python',
  'password' : '123',
  'device_type': 'cisco_ios',
  'host': ip
  }
  devices.append(dev)
  tasks = [task(dev) for dev in devices]
  await asyncio.wait(tasks)
  
 start_time = time.time()
 asyncio.run(run())
 print ('Time elapsed: %.2f'%(time.time()-start_time))

执行代码看效果:

可以看到通过netdev提供的“异步”方式,我们仅仅耗时5.15秒便跑完了脚本,对5台交换机完成了同样的配置!

另外,除了netdev外,pexpect模块也支持异步并行,有兴趣的读者可以自行参阅其他资料了解。

相关推荐

qq恢复系统常见问题(qq恢复系统常见问题及答案)

QQ好友恢复系统一直显示服务器频繁有可能是系统的问题,你的qq重新更新一下,或者你卸载了重新下载一下就有可能好了。您好,很高兴为您解答:您可以试试清空下IE内存,然后关掉不必要的程序,尽量在电脑运...

win10自带的office不见了(win10自带的office在哪个文件夹)

win10系统的office在电脑硬盘office的安装目录里,具体打开安装目录的操作如下:1、首先我们右键点击word,打开方式,选择默认程序打开。2、在默认框打钩,点击【浏览】。3、打开你安装of...

华为官网序列号查询入口(华为官网序列号查询入口手写笔)
  • 华为官网序列号查询入口(华为官网序列号查询入口手写笔)
  • 华为官网序列号查询入口(华为官网序列号查询入口手写笔)
  • 华为官网序列号查询入口(华为官网序列号查询入口手写笔)
  • 华为官网序列号查询入口(华为官网序列号查询入口手写笔)
手机主题美化包(手机主题美化包下载)
  • 手机主题美化包(手机主题美化包下载)
  • 手机主题美化包(手机主题美化包下载)
  • 手机主题美化包(手机主题美化包下载)
  • 手机主题美化包(手机主题美化包下载)
w10系统我的电脑在哪里(windows10 我的电脑在哪)

首先,打开Windows10系统,可以看到当前桌面上没有“我的电脑”。二、然后,在桌面上鼠标右键都加空白处,在右键菜单中选择“个性化”,点击打开。三、然后,在窗口中左侧选择“更改桌面图标”,点击打开。...

2500电脑组装最强配置(2500左右组装电脑主机配置清单)

两千五百元组装电脑,但配置只能是一般。台式机分为主机和显示器两个主体,按这个价格,显示器只能配置一般的,大约两百多元价格,其余都用来组装主机,主机包含机箱,电源,排风扇,电脑主板及内存,电脑处理器,声...

小米手机定时关机怎么设置(如何让小米手机定时关机)
小米手机定时关机怎么设置(如何让小米手机定时关机)

1、从设置菜单中找到电池与性能选项。      2、选择电池版块,点击定时开关机。      3、将定时开机右边的按钮开...

2025-12-28 02:51 off999

磁盘删除的文件怎么恢复(磁盘误删怎么恢复)

可以恢复,因为删除文件时,其实只是把表头删除了,后面的数据并没有删除,直到下一次进行写磁盘操作需要占用节点所在位置时,才会把相应的数据覆盖掉。所以,就算你误删了文件之后又进行了其他写磁盘操作,只要没有...

qq自动回复内容古风(qq自动回复古文)
qq自动回复内容古风(qq自动回复古文)

1、抽剑相助,搭救无辜,却引来杀身之祸。那女子故作柔弱,假装爱慕,只为那本剑谱。2、只缘感君一回顾,使我思君朝与暮。3、相知相惜若可谓缘,不负韶华年。4、看那天地日月,恒静无言;青山长河,世代绵延;就像在我心中,你从未离去,也从未改变。5、...

2025-12-28 01:51 off999

惠普电脑bios设置u盘启动(惠普 bios u盘启动)

惠普电脑bios设置u盘启动:1、插上制作好的u启动启动盘的u盘并启动电脑,在进入开机画面的时候按“f2”进入bios界面;2、进入bios界面之后切换到“boot”,准备设置u盘启动;3、这里在键盘...

win7优化开机启动项(windows10启动项优化)

开机出现错误0xc0000017无法开机错误的解决办法。1、就是system文件丢失了。2、如果想来恢复正常,需要有U盘或者光盘的pe系统,在pe下修复。3、本身C:\Windows\System32...

联想笔记本电脑系统恢复出厂设置
  • 联想笔记本电脑系统恢复出厂设置
  • 联想笔记本电脑系统恢复出厂设置
  • 联想笔记本电脑系统恢复出厂设置
  • 联想笔记本电脑系统恢复出厂设置
默认浏览器怎么改(软件默认浏览器怎么改)

在浏览器中设置默认浏览器的方法略有不同,以下是在常见的几个浏览器中设置默认浏览器的方法:1.在Windows10中设置Edge浏览器为默认浏览器:  a.打开&#...

显卡驱动程序是什么

NVIDIA驱动是一种软件,用于管理安装在计算机上的NVIDIA图形处理器,以确保它们正常运行。NVIDIA是一家知名的GPU(图形处理器)制造商,提供各种高性能显卡和集成GPU,这些设备需要相应的驱...

电脑的网络怎么连接wifi(台式电脑wifi在哪里打开)
  • 电脑的网络怎么连接wifi(台式电脑wifi在哪里打开)
  • 电脑的网络怎么连接wifi(台式电脑wifi在哪里打开)
  • 电脑的网络怎么连接wifi(台式电脑wifi在哪里打开)
  • 电脑的网络怎么连接wifi(台式电脑wifi在哪里打开)

取消回复欢迎 发表评论: