python高性能代码之多线程优化
以常见的端口扫描器为实例
端口扫描器的原理很简单,操作socket来判断连接状态确定主机端口的开放情况。
import socket
def scan(port):
s = socket.socket()
if s.connect_ex(('localhost', port)) == 0:
print port, 'open'
s.close()
if __name__ == '__main__':
map(scan,range(1,65536))
这是一个socket扫描器的基本代码。
但是如果直接运行会等待很长时间都没有反应,这是因为socket是阻塞的,到等待每个连接超时后才会进入下一个连接。
给这段代码加一个超时
s.settimeout(0.1)
完整的代码如下
import socket
def scan(port):
s = socket.socket()
s = settimeont(0.1)
if s.connect_ex(('localhost', port)) == 0:
print port, 'open'
s.close()
if __name__ == '__main__':
map(scan,range(1,65536))
本文的重点不在于扫描器功能部分。而重点在于代码质量的提升和优化从而提升代码的运行效率。
多线程版本:
import socket
import threading
def scan(port):
s = socket.socket()
s.settimeout(0.1)
if s.connect_ex(('localhost', port)) == 0:
print port, 'open'
s.close() if __name__ == '__main__':
threads = [threading.Thread(target=scan, args=(i,)) for i in xrange(1,65536)]
map(lambda x:x.start(),threads)
Run起来,速度确实快了不少,但是抛出了异常:thread.error: can't start new thread
这个进程开启了65535个线程,有两种可能,一种是超过最大线程数了,一种是超过最大socket句柄数了。在linux可以通过ulimit来修改。
如果不修改最大限制,怎么用多线程不报错呢?
加个queue,变成生产者-消费者模式,开固定线程。
多线程+队列版本:
import socket
import threading
from Queue import Queue
def scan(port):
s = socket.socket()
s.settimeout(0.1)
if s.connect_ex(('localhost', port)) == 0:
print port, 'open'
s.close() def worker():
while not q.empty():
port = q.get()
try:
scan(port)
finally:
q.task_done() if __name__ == '__main__':
q = Queue()
map(q.put,xrange(1,65535))
threads = [threading.Thread(target=worker) for i in xrange(500)]
map(lambda x:x.start(),threads)
q.join()
开500个线程,不停的从队列中取出任务来进行...
multiprocessing + 队列版本:
总不能开65535个进程吧?还是用生产者消费者模式
import socket
import multiprocessing
def scan(port):
s = socket.socket()
s.settimeout(0.1)
if s.connect_ex(('localhost', port)) == 0:
print port, 'open'
s.close() def worker(q):
while not q.empty():
port = q.get()
try:
scan(port)
finally:
q.task_done() if __name__ == '__main__':
q = multiprocessing.JoinableQueue()
map(q.put,xrange(1,65535))
jobs = [multiprocessing.Process(target=worker, args=(q,)) for i in xrange(100)]
map(lambda x:x.start(),jobs)
注意这里把队列作为一个参数传入到worker中去,因为是process safe的queue,不然会报错。
还有用的是JoinableQueue(),顾名思义就是可以join()的。
gevent的spawn版本:
from gevent import monkey; monkey.patch_all();
import gevent
import socket
...
if __name__ == '__main__':
threads = [gevent.spawn(scan, i) for i in xrange(1,65536)]
gevent.joinall(threads)
注意monkey patch必须在被patch的东西之前import,不然会Exception KeyError.比如不能先import threading,再monkey patch.
gevent的Pool版本:
from gevent import monkey; monkey.patch_all();
import socket
from gevent.pool import Pool
...
if __name__ == '__main__':
pool = Pool(500)
pool.map(scan,xrange(1,65536))
pool.join()
concurrent.futures版本:
import socket
from Queue import Queue
from concurrent.futures import ThreadPoolExecutor
...
if __name__ == '__main__':
q = Queue()
map(q.put,xrange(1,65536))
with ThreadPoolExecutor(max_workers=500) as executor:
for i in range(500):
executor.submit(worker,q)
python高性能代码之多线程优化的更多相关文章
- uiautomatorviewer 优化定位符生成,支持生成Java,Python自动化代码
项目介绍 二次开发 uiautomatorviewer 优化定位符生成,支持生成Java,Python自动化代码,修复自带工具画面有动态加载时截图失败问题,优化自带工具截图速度 ,实现类似录制脚本功能 ...
- python面试题之多线程好吗?列举一些让Python代码以并行方式运行的方法
答案 Python并不支持真正意义上的多线程.Python中提供了多线程包,但是如果你想通过多线程提高代码的速度,使用多线程包并不是个好主意.Python中有一个被称为Global Interpret ...
- HBase 高性能获取数据(多线程批量式解决办法) + MySQL和HBase性能测试比较
摘要: 在前篇博客里已经讲述了通过一个自定义 HBase Filter来获取数据的办法,在末尾指出此办法的性能是不能满足应用要求的,很显然对于如此成熟的HBase来说,高性能获取数据应该不是问题. ...
- Python猫荐书系列之五:Python高性能编程
稍微关心编程语言的使用趋势的人都知道,最近几年,国内最火的两种语言非 Python 与 Go 莫属,于是,隔三差五就会有人问:这两种语言谁更厉害/好找工作/高工资…… 对于编程语言的争论,就是猿界的生 ...
- Python实现代码统计工具——终极加速篇
Python实现代码统计工具--终极加速篇 声明 本文对于先前系列文章中实现的C/Python代码统计工具(CPLineCounter),通过C扩展接口重写核心算法加以优化,并与网上常见的统计工具做对 ...
- 《Python高性能编程》——列表、元组、集合、字典特性及创建过程
这里的内容仅仅是本人阅读<Python高性能编程>后总结的一些知识,用于自己更好的了解Python机制.本人现在并不从事计算密集型工作:人工智能.数据分析等.仅仅只是出于好奇而去阅读这本书 ...
- python高性能编程方法一
python高性能编程方法一 阅读 Zen of Python,在Python解析器中输入 import this. 一个犀利的Python新手可能会注意到"解析"一词, 认为 ...
- python单例模式的实现与优化
python单例模式的实现与优化 阅读目录(Content) 单例模式 实现单例模式的几种方式 1.使用模块 2.使用装饰器 3.使用类 4.基于__new__方法实现(推荐使用,方便) 5.基于me ...
- Python编码/文件读取/多线程
Python编码/文件读取/多线程 个人笔记~~记录才有成长 编码/文件读取/多线程 编码 常用的一般是gbk.utf-8,而在python中字符串一般是用Unicode来操作,这样才能按照单个字 ...
随机推荐
- BizTalk开发系列(二十四) BizTalk项目框架建议
Asp.NET有MVC框架,大部份的开发都是按照MVC进行的.BizTalk是面向消息的开发,不能完全采用分层的开发模式.而微软只提供了 BizTalk项目开发的基本策略,通过分析相关的Complex ...
- EntityFramework code first 一些常用的约束特性
参阅: https://msdn.microsoft.com/zh-cn/data/jj591583 1. 主键 public class Test { //名称为 ID 的属性会自动映射为主键(自增 ...
- 生成器(generator)内部解析
#http://kb.cnblogs.com/page/87128/(未看完)
- Android百分比布局支持库介绍——com.android.support:percent(转)
转载自http://www.apkbus.com/forum.php?mod=viewthread&tid=244752&extra=&_dsign=0b699c42 在此之前 ...
- spring 以Ant Build方式运行build.xml文件,报warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds 的解决办法
Buildfile: F:\experience\spring_pdf\sourcecode\example1\build.xml compile: [javac] F:\experience\spr ...
- ionic获取焦点
功能需求:点击按钮后获取input输入框的焦点 获取焦点用jq focus()不成功,因为angular也不推荐,所以网上找了一个在focus封装成指令的方法 指令写法: .directive('my ...
- js日期字符串增加天数的函数
//日期加天数的方法 //dataStr日期字符串 //dayCount 要增加的天数 //return 增加n天后的日期字符串 function dateAddDays(dataStr,dayCou ...
- C#.NET序列化XML、JSON、二进制微软自带DLL与newtonsoft(json.net)
序列化是将对象转换成另一种格式(XML.json.二进制byte[]) JSON序列化 .NET中有三种常用的JSON序列化的类,分别是: Newtonsoft.Json.JsonConvert类(推 ...
- find常用参数详解
find常用参数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在linux系统中,在init 3模式情况下都是命令行模式,这个时候我们想要找到一个文件的就得依赖一个非常好用的 ...
- 微信端应用 ionic实现texarea 自适应高度
最近公司项目,做微信端用到texarea 需要实现自适应高度的功能 当然自适应高度的方法很多网上找一大片,最直接的方式就是在使用到texarea的controller中添加js代码事件来实现,这中方式 ...