python单线程,多线程和协程速度对比
在某些应用场景下,想要提高python的并发能力,可以使用多线程,或者协程。比如网络爬虫,数据库操作等一些IO密集型的操作。下面对比python单线程,多线程和协程在网络爬虫场景下的速度。
一,单线程。
单线程代
1 #!/usr/bin/env
2 # coding:utf8
3 # Author: hz_oracle import MySQLdb
import gevent
import requests
import time class DbHandler(object):
def __init__(self, host, port, user, pwd, dbname):
self.host = host
self.port = port
self.user = user
self.pwd = pwd
self.db = dbname def db_conn(self):
try:
self.conn = MySQLdb.connect(host=self.host, port=self.port, user=self.user, passwd=self.pwd, db=self.db, charset="utf8")
self.cursor = self.conn.cursor()
return 1
except Exception as e:
return 0 def get_urls(self, limitation):
sql = """select pic from picurltable limit %s""" % limitation
urls_list = list()
try:
self.cursor.execute(sql)
fetchresult = self.cursor.fetchall()
for line in fetchresult:
urls_list.append(line[0])
print len(urls_list)
except Exception as e:
print u"数据库查询失败:%s" % e
return []
return urls_list def db_close(self):
self.conn.close() def get_pic(url):
try:
pic_obj = requests.get(url).content
except Exception as e:
print u"图片出错"
return ""
filename = url.split('/')[-2]
file_path = "./picture/" + filename + '.jpg'
fp = file(file_path, 'wb')
fp.write(pic_obj)
fp.close()
return "ok" def main():
start_time = time.time()
db_obj = DbHandler(host='127.0.0.1', port=3306, user='root', pwd='123456', dbname='pic')
db_obj.db_conn()
url_list = db_obj.get_urls(100)
map(get_pic, url_list)
#for url in url_list:
# get_pic(url)
end_time = time.time()
costtime = float(end_time) - float(start_time)
print costtime
print "download END" if __name__ == "__main__":
main()
运行结果
100
45.1282339096
download END
单线程情况下,下载100张图片花了45秒。
再来看多线程的情况下。
#!/usr/bin/env python
# coding:utf8
# Author: hz_oracle import MySQLdb
import gevent
import requests
import time
import threading
import Queue lock1 = threading.RLock()
url_queue = Queue.Queue()
urls_list = list() class DbHandler(object):
def __init__(self, host, port, user, pwd, dbname):
self.host = host
self.port = port
self.user = user
self.pwd = pwd
self.db = dbname def db_conn(self):
try:
self.conn = MySQLdb.connect(host=self.host, port=self.port, user=self.user, passwd=self.pwd, db=self.db, charset="utf8")
self.cursor = self.conn.cursor()
return 1
except Exception as e:
return 0 def get_urls(self, limitation):
sql = """select pic from picurltable limit %s""" % limitation
try:
self.cursor.execute(sql)
fetchresult = self.cursor.fetchall()
for line in fetchresult:
url_queue.put(line[0])
except Exception as e:
print u"数据库查询失败:%s" % e
return 0
return 1 def db_close(self):
self.conn.close() class MyThread(threading.Thread):
def __init__(self):
super(MyThread, self).__init__() def run(self):
url = url_queue.get()
try:
pic_obj = requests.get(url).content
except Exception as e:
print u"图片出错"
return ""
filename = url.split('/')[-2]
file_path = "./picture/" + filename + '.jpg'
fp = file(file_path, 'wb')
fp.write(pic_obj)
fp.close() def main():
start_time = time.time()
db_obj = DbHandler(host='127.0.0.1', port=3306, user='root', pwd='', dbname='pic')
db_obj.db_conn()
db_obj.get_urls(100)
for i in range(100):
i = MyThread()
i.start()
while True:
if threading.active_count()<=1:
break
end_time = time.time()
costtime = float(end_time) - float(start_time)
print costtime
print "download END" if __name__ == "__main__":
main()
运行结果
15.408192873
download END
启用100个线程发现只要花15秒即可完成任务,100个线程可能不是最优的方案,但较单线程有很明显的提升。接着再来看协程。
协程代码
#!/usr/bin/env python
# coding:utf8
# Author: hz_oracle import MySQLdb
import requests
import time
import threading
import Queue from gevent import monkey; monkey.patch_all()
import gevent class DbHandler(object):
def __init__(self, host, port, user, pwd, dbname):
self.host = host
self.port = port
self.user = user
self.pwd = pwd
self.db = dbname def db_conn(self):
try:
self.conn = MySQLdb.connect(host=self.host, port=self.port, user=self.user, passwd=self.pwd, db=self.db, charset="utf8")
self.cursor = self.conn.cursor()
return 1
except Exception as e:
return 0 def get_urls(self, limitation):
urls_list = list()
sql = """select pic from picurltable limit %s""" % limitation
try:
self.cursor.execute(sql)
fetchresult = self.cursor.fetchall()
for line in fetchresult:
urls_list.append(line[0])
except Exception as e:
print u"数据库查询失败:%s" % e
return []
return urls_list def db_close(self):
self.conn.close() def get_pic(url):
try:
pic_obj = requests.get(url).content
except Exception as e:
print u"图片出错"
return ""
filename = url.split('/')[-2]
file_path = "./picture/" + filename + '.jpg'
fp = file(file_path, 'wb')
fp.write(pic_obj)
fp.close()
return "ok" def main():
start_time = time.time()
db_obj = DbHandler(host='127.0.0.1', port=3306, user='root', pwd='123456', dbname='pic')
db_obj.db_conn()
url_list = db_obj.get_urls(100)
gevent.joinall([gevent.spawn(get_pic,url) for url in url_list]) end_time = time.time()
costtime = float(end_time) - float(start_time)
print costtime
print "download END" if __name__ == "__main__":
main()
运行结果
10.6234440804
download END
使用协程发现只花了10秒多,也就是三种方法中最快的。
总结:
三种方法中,单线程最慢,多线程次之,而协程最快。 不过如果对多线程进行优化,也可能变快,这里不讨论。
python单线程,多线程和协程速度对比的更多相关文章
- Python并发编程二(多线程、协程、IO模型)
1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...
- python 多进程,多线程,协程
在我们实际编码中,会遇到一些并行的任务,因为单个任务无法最大限度的使用计算机资源.使用并行任务,可以提高代码效率,最大限度的发挥计算机的性能.python实现并行任务可以有多进程,多线程,协程等方式. ...
- Python并发编程——多线程与协程
Pythpn并发编程--多线程与协程 目录 Pythpn并发编程--多线程与协程 1. 进程与线程 1.1 概念上 1.2 多进程与多线程--同时执行多个任务 2. 并发和并行 3. Python多线 ...
- 深入浅析python中的多进程、多线程、协程
深入浅析python中的多进程.多线程.协程 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源 ...
- python并发编程之协程知识点
由线程遗留下的问题:GIL导致多个线程不能真正的并行,CPython中多个线程不能并行 单线程实现并发:切换+保存状态 第一种方法:使用yield,yield可以保存状态.yield的状态保存与操作系 ...
- Cpython解释器下实现并发编程——多进程、多线程、协程、IO模型
一.背景知识 进程即正在执行的一个过程.进程是对正在运行的程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所有内容都 ...
- Python之并发编程-协程
目录 一.介绍 二. yield.greenlet.gevent介绍 1.yield 2.greenlet 3.gevent 一.介绍 协程:是单线程下的并发,又称微线程,纤程.英文名Coroutin ...
- python进阶——进程/线程/协程
1 python线程 python中Threading模块用于提供线程相关的操作,线程是应用程序中执行的最小单元. #!/usr/bin/env python # -*- coding:utf-8 - ...
- 32 python 并发编程之协程
一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...
随机推荐
- JSP自定义标签必知必会
自定义标签技术自sun公司发布以来,便一向很受欢迎!下面我就来谈一谈如何实现自定义标签,以及如何使用自定义标签. 如何实现自定义标签 首先我们应该知道原理,不管是标签还是JSP,本身实际上都会被JSP ...
- Cytoscape源码下载地址和编译办法
开发环境:Windows2008 R2 64位+Jdk1.7+Maven3.2.3 前提条件:安装好JDK1.7到C:\Program Files\Java\jdk1.7.0_67,下载好Maven并 ...
- C++编译器对属性和方法的处理机制
C++中的class从面向对象理论出发,将变量(属性)和函数(方法)集中定义在一起,用于描述现实世界中的类.从计算机的角度,程序依然由数据段和代码段构成. C++编译器如何完成面向对象理论到计算机程序 ...
- java根据概率生成数字
/** * JAVA 返回随机数,并根据概率.比率 * @author zhanglei * */ public class MathRandom { /** * 0出现的概率为%50 */ publ ...
- iOS中 自定义cell升级版 (高级)
接上次分享的自定义cell进行了优化:http://blog.csdn.net/qq_31810357/article/details/49611255 指定根视图: self.window.root ...
- Linux Debugging(六): 动态库注入、ltrace、strace、Valgrind
实际上,Linux的调试方法非常多,针对不同的问题,不同的场景,不同的应用,都有不同的方法.很难去概括.本篇文章主要涉及本专栏还没有涵盖,但是的确有很重要的方法.本文主要包括动态库注入调试:使用ltr ...
- Linux下修改主机名步骤
Linux下修改主机名为gpdb 步骤一.运行vi /etc/sysconfig/network命令 NETWORKING=yesHOSTNAME=gpdb 步骤二.运行hostname gpdb命令 ...
- (NO.00003)iOS游戏简单的机器人投射游戏成形记(八)
回到Xcode,新建ArmStatic类,继承于CCSprite.同样在初始化方法中打开用户交互. 下面添加触摸回调方法,touchBegan以及touchMoved方法和Arm基本相同,主要不同处在 ...
- 小强的HTML5移动开发之路(20)——HTML5 Web SQL Database
来自:http://blog.csdn.net/dawanganban/article/details/18220761 一.Web Database介绍 WebSQL数据库API实际上不是HTML5 ...
- 如何设计一个web容器
开发一个web容器涉及很多不同方面不同层面的技术,例如通信层的知识,程序语言层面的知识等等,且一个可用的web容器是一个比较庞大的系统,要说清楚需要很长的篇幅,本文旨在介绍如何设计一个web容器,只探 ...