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正在运行一个任务,会在两种情况下切走去 ...
随机推荐
- 消息字节——MessageBytes
在tomcat核心处理中有这么一个需求--"为了提高编码性能,对于socket接收到的字节流不马上进行某种编码的转码,而是应该保留字节流的形式,在需要时.在指定编码时才进行转码工作" ...
- [GitHub]第三讲:简单分支操作
Git 最核心的操作对象是版本( commit ),最核心的操作技巧就是分支. 什么是分支? 仓库创建后,一旦有了新 commit,默认就会放到一个分支上,名字叫 master.前面咱们一直看到的多个 ...
- Mysql group by语句的优化
默认情况下,MySQL排序所有GROUP BY col1, col2, ....,查询的方法如同在查询中指定ORDER BY col1, col2, ....如果显式包括一个包含相同的列的ORDER ...
- Android样式(style)和主题(theme)资源介绍-android学习之旅(五十六)
样式(style)资源 代码示例 <?xml version="1.0" encoding="utf-8"?> <LinearLayout x ...
- UNIX环境高级编程——信号之kill、raise、killpg、alarm、pause、abort、sleep、usleep、nanosleep和setitimer函数
一.kill, raise, killpg 函数 int kill(pid_t pid, int sig); int raise(int sig); int killpg(int pgrp, int ...
- shell的case语句简述(shell的流控制)
shell流控制:http://www.cnblogs.com/yunjiaofeifei/archive/2012/06/12/2546208.html 1.if then else 语句 if t ...
- 敦泰FT6X06单层自容调屏
总的概括来说,自电容调屏在配置好通道个数和顺序后,只需调整AFE相关的设置参数使各通道的Raw Data和CI值符合定义的标准即可.– AFE是模拟前端的缩写-Analog Front End• Ra ...
- MySQL学习笔记_4_MySQL创建数据表(下)
MySQL创建数据表(下) 五.数据表类型及存储位置 1.MySQL与大多数数据库不同,MySQL有一个存储引擎概念.MySQL可以针对不同的存储需求选择不同的存储引擎. 2. showengines ...
- Android开发你不知道的TIPS
1.Space space是Android 4.0中新增的一个控件,它实际上可以用来分隔不同的控件,其中形成一个空白的区域.这是一个轻量级的视图组件,它可以跳过Draw,对于需要占位符的任何场景来说都 ...
- AngularJS进阶(十)AngularJS改变元素显示状态
AngularJS改变元素显示状态 前言 本文描述使用AngularJS提供的ng-show和ng-hide指令实现自动监听某布尔型变量来改变元素显示状态. 控制html元素显示和隐藏有n种方法:ht ...