python 协程池和pool.map用法
一、问题描述
现在有一段代码,需要扫描一个网段内的ip地址,是否可以ping通。
执行起来效率太慢,需要使用协程。
#!/usr/bin/env python
# -*- coding: utf-8 -*- import os
import time
import signal
import subprocess
import gevent
import gevent.pool
from gevent import monkey;monkey.patch_all() def custom_print(content,colour='white'):
"""
写入日志文件
:param content: 内容
:param colour: 颜色
:return: None
"""
# 颜色代码
colour_dict = {
'red': 31, # 红色
'green': 32, # 绿色
'yellow': 33, # 黄色
'blue': 34, # 蓝色
'purple_red': 35, # 紫红色
'bluish_blue': 36, # 浅蓝色
'white': 37, # 白色
}
choice = colour_dict.get(colour) # 选择颜色 info = "\033[1;{};1m{}\033[0m".format(choice, content)
print(info) def execute_linux2(cmd, timeout=10, skip=False):
"""
执行linux命令,返回list
:param cmd: linux命令
:param timeout: 超时时间,生产环境, 特别卡, 因此要3秒
:param skip: 是否跳过超时限制
:return: list
"""
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE,shell=True,close_fds=True,preexec_fn=os.setsid) t_beginning = time.time() # 开始时间
while True:
if p.poll() is not None:
break
seconds_passed = time.time() - t_beginning
if not skip:
if seconds_passed > timeout:
# p.terminate()
# p.kill()
# raise TimeoutError(cmd, timeout)
custom_print('错误, 命令: {},本地执行超时!'.format(cmd),"red")
# 当shell=True时,只有os.killpg才能kill子进程
try:
# time.sleep(1)
os.killpg(p.pid, signal.SIGUSR1)
except Exception as e:
pass
return False result = p.stdout.readlines() # 结果输出列表
return result class NetworkTest(object):
def __init__(self):
self.flag_list = [] def check_ping(self,ip):
"""
检查ping
:param ip: ip地址
:return: none
"""
cmd = "ping %s -c 2" % ip
# print(cmd)
# 本机执行命令
res = execute_linux2(cmd,2)
# print(res)
if not res:
custom_print("错误, 执行命令: {} 失败".format(cmd), "red")
self.flag_list.append(False)
return False res.pop() # 删除最后一个元素
last_row = res.pop().decode('utf-8').strip() # 再次获取最后一行结果
if not last_row:
custom_print("错误,执行命令: {} 异常","red")
self.flag_list.append(False)
return False res = last_row.split() # 切割结果
# print(res,type(res),len(res))
if len(res) <10:
custom_print("错误,切割 ping 结果异常","red")
self.flag_list.append(False)
return False if res[5] == "0%": # 判断丢包率
custom_print("正常, ip: {} ping正常 丢包率0%".format(ip), "green")
else:
self.flag_list.append(False)
custom_print("错误, ip: {} ping异常 丢包率100%".format(ip), "red") def main(self):
"""
主程序
:return:
"""
for num in range(1, 256):
ip = '192.168.10.{}'.format(num)
self.check_ping(ip) if __name__ == '__main__':
startime = time.time() # 开始时间 NetworkTest().main() endtime = time.time()
take_time = endtime - startime if take_time < 1: # 判断不足1秒时
take_time = 1 # 设置为1秒
# 计算花费时间
m, s = divmod(take_time, 60)
h, m = divmod(m, 60) custom_print("本次花费时间 %02d:%02d:%02d" % (h, m, s),"green")
改造成,协程执行。
#!/usr/bin/env python
# -*- coding: utf-8 -*- import os
import time
import signal
import subprocess
import gevent
import gevent.pool
from gevent import monkey;monkey.patch_all() def custom_print(content,colour='white'):
"""
写入日志文件
:param content: 内容
:param colour: 颜色
:return: None
"""
# 颜色代码
colour_dict = {
'red': 31, # 红色
'green': 32, # 绿色
'yellow': 33, # 黄色
'blue': 34, # 蓝色
'purple_red': 35, # 紫红色
'bluish_blue': 36, # 浅蓝色
'white': 37, # 白色
}
choice = colour_dict.get(colour) # 选择颜色 info = "\033[1;{};1m{}\033[0m".format(choice, content)
print(info) def execute_linux2(cmd, timeout=10, skip=False):
"""
执行linux命令,返回list
:param cmd: linux命令
:param timeout: 超时时间,生产环境, 特别卡, 因此要3秒
:param skip: 是否跳过超时限制
:return: list
"""
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE,shell=True,close_fds=True,preexec_fn=os.setsid) t_beginning = time.time() # 开始时间
while True:
if p.poll() is not None:
break
seconds_passed = time.time() - t_beginning
if not skip:
if seconds_passed > timeout:
# p.terminate()
# p.kill()
# raise TimeoutError(cmd, timeout)
custom_print('错误, 命令: {},本地执行超时!'.format(cmd),"red")
# 当shell=True时,只有os.killpg才能kill子进程
try:
# time.sleep(1)
os.killpg(p.pid, signal.SIGUSR1)
except Exception as e:
pass
return False result = p.stdout.readlines() # 结果输出列表
return result class NetworkTest(object):
def __init__(self):
self.flag_list = [] def check_ping(self,ip):
"""
检查ping
:param ip: ip地址
:return: none
"""
cmd = "ping %s -c 2" % ip
# print(cmd)
# 本机执行命令
res = execute_linux2(cmd,2)
# print(res)
if not res:
custom_print("错误, 执行命令: {} 失败".format(cmd), "red")
self.flag_list.append(False)
return False res.pop() # 删除最后一个元素
last_row = res.pop().decode('utf-8').strip() # 再次获取最后一行结果
if not last_row:
custom_print("错误,执行命令: {} 异常","red")
self.flag_list.append(False)
return False res = last_row.split() # 切割结果
# print(res,type(res),len(res))
if len(res) <10:
custom_print("错误,切割 ping 结果异常","red")
self.flag_list.append(False)
return False if res[5] == "0%": # 判断丢包率
custom_print("正常, ip: {} ping正常 丢包率0%".format(ip), "green")
else:
self.flag_list.append(False)
custom_print("错误, ip: {} ping异常 丢包率100%".format(ip), "red") def main(self):
"""
主程序
:return:
"""
process_list = []
for num in range(1, 256):
ip = '192.168.10.{}'.format(num)
# self.check_ping(ip)
# 将任务加到列表中
process_list.append(gevent.spawn(self.check_ping, ip)) gevent.joinall(process_list) # 等待所有协程结束 if __name__ == '__main__':
startime = time.time() # 开始时间 NetworkTest().main() endtime = time.time()
take_time = endtime - startime if take_time < 1: # 判断不足1秒时
take_time = 1 # 设置为1秒
# 计算花费时间
m, s = divmod(take_time, 60)
h, m = divmod(m, 60) custom_print("本次花费时间 %02d:%02d:%02d" % (h, m, s),"green")
执行输出:
...
错误, 命令: ping 192.168.10.250 -c 2,本地执行超时!
错误, 执行命令: ping 192.168.10.250 -c 2 失败
错误, 命令: ping 192.168.10.255 -c 2,本地执行超时!
错误, 执行命令: ping 192.168.10.255 -c 2 失败
本次花费时间 00:00:07
注意:切勿在windows系统中运行,否则会报错
AttributeError: module 'os' has no attribute 'setsid'
二、使用协程池
上面直接将所有任务加到列表中,然后一次性,全部异步执行。那么同一时刻,最多有多少任务执行呢?
不知道,可能有256个吧?
注意:如果这个一个很耗CPU的程序,可能会导致服务器,直接卡死。
那么,我们应该要限制它的并发数。这个时候,需要使用协程池,固定并发数。
比如:固定为100个
#!/usr/bin/env python
# -*- coding: utf-8 -*- import os
import time
import signal
import subprocess
import gevent
import gevent.pool
from gevent import monkey;monkey.patch_all() def custom_print(content,colour='white'):
"""
写入日志文件
:param content: 内容
:param colour: 颜色
:return: None
"""
# 颜色代码
colour_dict = {
'red': 31, # 红色
'green': 32, # 绿色
'yellow': 33, # 黄色
'blue': 34, # 蓝色
'purple_red': 35, # 紫红色
'bluish_blue': 36, # 浅蓝色
'white': 37, # 白色
}
choice = colour_dict.get(colour) # 选择颜色 info = "\033[1;{};1m{}\033[0m".format(choice, content)
print(info) def execute_linux2(cmd, timeout=10, skip=False):
"""
执行linux命令,返回list
:param cmd: linux命令
:param timeout: 超时时间,生产环境, 特别卡, 因此要3秒
:param skip: 是否跳过超时限制
:return: list
"""
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE,shell=True,close_fds=True,preexec_fn=os.setsid) t_beginning = time.time() # 开始时间
while True:
if p.poll() is not None:
break
seconds_passed = time.time() - t_beginning
if not skip:
if seconds_passed > timeout:
# p.terminate()
# p.kill()
# raise TimeoutError(cmd, timeout)
custom_print('错误, 命令: {},本地执行超时!'.format(cmd),"red")
# 当shell=True时,只有os.killpg才能kill子进程
try:
# time.sleep(1)
os.killpg(p.pid, signal.SIGUSR1)
except Exception as e:
pass
return False result = p.stdout.readlines() # 结果输出列表
return result class NetworkTest(object):
def __init__(self):
self.flag_list = [] def check_ping(self,ip):
"""
检查ping
:param ip: ip地址
:return: none
"""
cmd = "ping %s -c 2" % ip
# print(cmd)
# 本机执行命令
res = execute_linux2(cmd,2)
# print(res)
if not res:
custom_print("错误, 执行命令: {} 失败".format(cmd), "red")
self.flag_list.append(False)
return False res.pop() # 删除最后一个元素
last_row = res.pop().decode('utf-8').strip() # 再次获取最后一行结果
if not last_row:
custom_print("错误,执行命令: {} 异常","red")
self.flag_list.append(False)
return False res = last_row.split() # 切割结果
# print(res,type(res),len(res))
if len(res) <10:
custom_print("错误,切割 ping 结果异常","red")
self.flag_list.append(False)
return False if res[5] == "0%": # 判断丢包率
custom_print("正常, ip: {} ping正常 丢包率0%".format(ip), "green")
else:
self.flag_list.append(False)
custom_print("错误, ip: {} ping异常 丢包率100%".format(ip), "red") def main(self):
"""
主程序
:return:
"""
process_list = []
pool= gevent.pool.Pool(100) # 协程池固定为100个
for num in range(1, 256):
ip = '192.168.10.{}'.format(num)
# self.check_ping(ip)
# 将任务加到列表中
process_list.append(pool.spawn(self.check_ping, ip)) gevent.joinall(process_list) # 等待所有协程结束 if __name__ == '__main__':
startime = time.time() # 开始时间 NetworkTest().main() endtime = time.time()
take_time = endtime - startime if take_time < 1: # 判断不足1秒时
take_time = 1 # 设置为1秒
# 计算花费时间
m, s = divmod(take_time, 60)
h, m = divmod(m, 60) custom_print("本次花费时间 %02d:%02d:%02d" % (h, m, s),"green")
再次执行,效果如下:
...
错误, 执行命令: ping 192.168.10.254 -c 2 失败
错误, 命令: ping 192.168.10.255 -c 2,本地执行超时!
错误, 执行命令: ping 192.168.10.255 -c 2 失败
本次花费时间 00:00:15
可以,发现花费的时间,明显要比上面慢了!
pool.map 单个参数
其实,还有一种写法,使用pool.map,语法如下:
pool.map(func,iterator)
比如:
pool.map(self.get_kernel, NODE_LIST)
注意:func是一个方法,iterator是一个迭代器。比如:list就是一个迭代器
使用map时,func只能接收一个参数。这个参数就是,遍历迭代器的每一个值。
使用map,完整代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*- import os
import time
import signal
import subprocess
import gevent
import gevent.pool
from gevent import monkey;monkey.patch_all() def custom_print(content,colour='white'):
"""
写入日志文件
:param content: 内容
:param colour: 颜色
:return: None
"""
# 颜色代码
colour_dict = {
'red': 31, # 红色
'green': 32, # 绿色
'yellow': 33, # 黄色
'blue': 34, # 蓝色
'purple_red': 35, # 紫红色
'bluish_blue': 36, # 浅蓝色
'white': 37, # 白色
}
choice = colour_dict.get(colour) # 选择颜色 info = "\033[1;{};1m{}\033[0m".format(choice, content)
print(info) def execute_linux2(cmd, timeout=10, skip=False):
"""
执行linux命令,返回list
:param cmd: linux命令
:param timeout: 超时时间,生产环境, 特别卡, 因此要3秒
:param skip: 是否跳过超时限制
:return: list
"""
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE,shell=True,close_fds=True,preexec_fn=os.setsid) t_beginning = time.time() # 开始时间
while True:
if p.poll() is not None:
break
seconds_passed = time.time() - t_beginning
if not skip:
if seconds_passed > timeout:
# p.terminate()
# p.kill()
# raise TimeoutError(cmd, timeout)
custom_print('错误, 命令: {},本地执行超时!'.format(cmd),"red")
# 当shell=True时,只有os.killpg才能kill子进程
try:
# time.sleep(1)
os.killpg(p.pid, signal.SIGUSR1)
except Exception as e:
pass
return False result = p.stdout.readlines() # 结果输出列表
return result class NetworkTest(object):
def __init__(self):
self.flag_list = [] def check_ping(self,ip):
"""
检查ping
:param ip: ip地址
:return: none
"""
cmd = "ping %s -c 2" % ip
# print(cmd)
# 本机执行命令
res = execute_linux2(cmd,2)
# print(res)
if not res:
custom_print("错误, 执行命令: {} 失败".format(cmd), "red")
self.flag_list.append(False)
return False res.pop() # 删除最后一个元素
last_row = res.pop().decode('utf-8').strip() # 再次获取最后一行结果
if not last_row:
custom_print("错误,执行命令: {} 异常","red")
self.flag_list.append(False)
return False res = last_row.split() # 切割结果
# print(res,type(res),len(res))
if len(res) <10:
custom_print("错误,切割 ping 结果异常","red")
self.flag_list.append(False)
return False if res[5] == "0%": # 判断丢包率
custom_print("正常, ip: {} ping正常 丢包率0%".format(ip), "green")
else:
self.flag_list.append(False)
custom_print("错误, ip: {} ping异常 丢包率100%".format(ip), "red") def main(self):
"""
主程序
:return:
"""
pool= gevent.pool.Pool(100) # 协程池固定为100个
ip_list = ["192.168.10.{}".format(i) for i in range(1, 256)]
# 使用pool.map,语法:pool.map(func,iterator)
pool.map(self.check_ping, ip_list) if __name__ == '__main__':
startime = time.time() # 开始时间 NetworkTest().main() endtime = time.time()
take_time = endtime - startime if take_time < 1: # 判断不足1秒时
take_time = 1 # 设置为1秒
# 计算花费时间
m, s = divmod(take_time, 60)
h, m = divmod(m, 60) custom_print("本次花费时间 %02d:%02d:%02d" % (h, m, s),"green")
注意:方法只有一个参数的情况下,使用pool.map,一行就可以搞定。这样看起来,比较精简!
pool.map 多参数
如果方法,有多个参数,需要借用偏函数实现。
完整代码如下:
#!/usr/bin/env python3
# coding: utf-8 #!/usr/bin/env python
# -*- coding: utf-8 -*- import os
import time
import signal
import subprocess
import gevent
import gevent.pool
from gevent import monkey;monkey.patch_all()
from functools import partial def custom_print(content,colour='white'):
"""
写入日志文件
:param content: 内容
:param colour: 颜色
:return: None
"""
# 颜色代码
colour_dict = {
'red': 31, # 红色
'green': 32, # 绿色
'yellow': 33, # 黄色
'blue': 34, # 蓝色
'purple_red': 35, # 紫红色
'bluish_blue': 36, # 浅蓝色
'white': 37, # 白色
}
choice = colour_dict.get(colour) # 选择颜色 info = "\033[1;{};1m{}\033[0m".format(choice, content)
print(info) def execute_linux2(cmd, timeout=10, skip=False):
"""
执行linux命令,返回list
:param cmd: linux命令
:param timeout: 超时时间,生产环境, 特别卡, 因此要3秒
:param skip: 是否跳过超时限制
:return: list
"""
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE,shell=True,close_fds=True,preexec_fn=os.setsid) t_beginning = time.time() # 开始时间
while True:
if p.poll() is not None:
break
seconds_passed = time.time() - t_beginning
if not skip:
if seconds_passed > timeout:
# p.terminate()
# p.kill()
# raise TimeoutError(cmd, timeout)
custom_print('错误, 命令: {},本地执行超时!'.format(cmd),"red")
# 当shell=True时,只有os.killpg才能kill子进程
try:
# time.sleep(1)
os.killpg(p.pid, signal.SIGUSR1)
except Exception as e:
pass
return False result = p.stdout.readlines() # 结果输出列表
return result class NetworkTest(object):
def __init__(self):
self.flag_list = [] def check_ping(self,ip,timeout):
"""
检查ping
:param ip: ip地址
:param ip: 超时时间
:return: none
"""
cmd = "ping %s -c 2 -W %s" %(ip,timeout)
# print(cmd)
# 本机执行命令
res = execute_linux2(cmd,2)
# print("res",res,"ip",ip,"len",len(res))
if not res:
custom_print("错误, 执行命令: {} 失败".format(cmd), "red")
self.flag_list.append(False)
return False if len(res) != 7:
custom_print("错误,执行命令: {} 异常".format(cmd), "red")
self.flag_list.append(False)
return False res.pop() # 删除最后一个元素
last_row = res.pop().decode('utf-8').strip() # 再次获取最后一行结果
if not last_row:
custom_print("错误,执行命令: {} 获取结果异常","red")
self.flag_list.append(False)
return False res = last_row.split() # 切割结果
# print(res,type(res),len(res))
if len(res) <10:
custom_print("错误,切割 ping 结果异常","red")
self.flag_list.append(False)
return False if res[5] == "0%": # 判断丢包率
custom_print("正常, ip: {} ping正常 丢包率0%".format(ip), "green")
else:
self.flag_list.append(False)
custom_print("错误, ip: {} ping异常 丢包率100%".format(ip), "red") def main(self):
"""
主程序
:return:
"""
pool= gevent.pool.Pool(100) # 协程池固定为100个
ip_list = ["192.168.0.{}".format(i) for i in range(1, 256)]
# 使用协程池,执行任务。语法: pool.map(func,iterator)
# partial使用偏函数传递参数
# 注意:func第一个参数,必须是迭代器遍历的值。后面的参数,必须使用有命名传参
pool.map(partial(self.check_ping, timeout=1), ip_list) if __name__ == '__main__':
startime = time.time() # 开始时间 NetworkTest().main() endtime = time.time()
take_time = endtime - startime if take_time < 1: # 判断不足1秒时
take_time = 1 # 设置为1秒
# 计算花费时间
m, s = divmod(take_time, 60)
h, m = divmod(m, 60) custom_print("本次花费时间 %02d:%02d:%02d" % (h, m, s),"green")
执行脚本,效果同上
本文参考链接:
https://www.cnblogs.com/c-x-a/p/9049651.html
python 协程池和pool.map用法的更多相关文章
- python 并发编程 基于gevent模块 协程池 实现并发的套接字通信
基于协程池 实现并发的套接字通信 客户端: from socket import * client = socket(AF_INET, SOCK_STREAM) client.connect(('12 ...
- python 并发编程 协程池
协程池 from gevent.pool import Pool from gevent import monkey;monkey.patch_all() import gevent from gev ...
- Python协程(真才实学,想学的进来)
真正有知识的人的成长过程,就像麦穗的成长过程:麦穗空的时候,麦子长得很快,麦穗骄傲地高高昂起,但是,麦穗成熟饱满时,它们开始谦虚,垂下麦芒. --蒙田<蒙田随笔全集> *** 上篇论述了关 ...
- python协程(yield、asyncio标准库、gevent第三方)、异步的实现
引言 同步:不同程序单元为了完成某个任务,在执行过程中需靠某种通信方式以协调一致,称这些程序单元是同步执行的. 例如购物系统中更新商品库存,需要用"行锁"作为通信信号,让不同的更新 ...
- python协程函数、递归、匿名函数与内置函数使用、模块与包
目录: 协程函数(yield生成器用法二) 面向过程编程 递归 匿名函数与内置函数的使用 模块 包 常用标准模块之re(正则表达式) 一.协程函数(yield生成器用法二) 1.生成器的语句形式 a. ...
- python3下multiprocessing、threading和gevent性能对比----暨进程池、线程池和协程池性能对比
python3下multiprocessing.threading和gevent性能对比----暨进程池.线程池和协程池性能对比 标签: python3 / 线程池 / multiprocessi ...
- 5分钟完全掌握Python协程
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 1. 协程相关的概念 1.1 进程和线程 进程(Process)是应用程序启动的实例,拥有代码.数据 ...
- fasthttp中的协程池实现
fasthttp中的协程池实现 协程池可以控制并行度,复用协程.fasthttp 比 net/http 效率高很多倍的重要原因,就是利用了协程池.实现并不复杂,我们可以参考他的设计,写出高性能的应用. ...
- golang协程池设计
Why Pool go自从出生就身带“高并发”的标签,其并发编程就是由groutine实现的,因其消耗资源低,性能高效,开发成本低的特性而被广泛应用到各种场景,例如服务端开发中使用的HTTP服务,在g ...
随机推荐
- svn项目迁移至gitlab
关于svn项目迁移有人可能会说,新建一个git项目,把原来的代码直接扔进去提交不完了吗.恩,是的,没错.但是为了保留之前的历史提交记录,还是得做下面的步骤 首先确保本地正常安装配置好git,具体步骤不 ...
- [USACO09DEC] Dizzy Cows 拓扑序
[USACO09DEC] Dizzy Cows 拓扑序 先对有向边跑拓扑排序,记录下每个点拓扑序,为了使最后的图不存在环,加入的\(p2\)条无向边\(u,v\)必须满足\(u\)拓扑序小于\(v\) ...
- 【洛谷P2270】奶牛的运算
题目链接 不难发现,每加一个括号,就相当于把括号内一段区间中的符号反转,于是就是看n-1个符号经过k次区间反转后的状态数,用插板法搞一搞就可以了 #include<iostream> #i ...
- 洛谷P1043数字游戏
题目 区间DP,将\(maxn[i][j][k]\)表示为i到j区间内分为k个区间所得到的最大值,\(minn\)表示最小值. 然后可以得到状态转移方程: \[maxn[i][j][k]= max(m ...
- Ps回调函数.拦截驱动模块原理+实现.
目录 一丶简介 二丶原理 1.原理 2.代码实现 3.效果 一丶简介 主要是讲解.内核中如何拦截模块加载的. 需要熟悉.内核回调的设置 PE知识. ShellCode 二丶原理 1.原理 原理是通过回 ...
- 修复LSP 解决不能上网问题
电脑突然不能上网,ping路由提示"传输失败,常见故障" 1, 打开CMD 2, 输入"netsh winsock reset" 回车 3, 重启电脑 LSP ...
- automapper 源中有多个属性类映射到同一个 目标中
CreateMap<TempBranchActivity, BranchActivityOutput>() .ConstructUsing((src, ctx) => ctx.Map ...
- [Beta]第五次 Scrum Meeting
[Beta]第五次 Scrum Meeting 写在前面 会议时间 会议时长 会议地点 2019/5/13 22:00 30min 大运村公寓6F楼道 附Github仓库:WEDO 例会照片 (一人上 ...
- 范仁义html+css课程---5、列表
范仁义html+css课程---5.列表 一.总结 一句话总结: 学会基本的使用有序列表.无序列表.定义列表,设置样式的话尽量通过css而不是属性 1.无序列表基本形式(实例)? ul标签包裹li标签 ...
- 最精简使用MORMOT
MORMOT是免费开源的SDK,它封装了HTTP.SYS,这是许多人使用它的原因,让人难以想像的是它居然支持DELPHI6及以上版本. 但MORMOT本身已经被封装的很庞大,它提供许多的单元,这让人不 ...