最近学习了多线程、多进程、协程以及IO多路复用,那么对于爬取数据来说,这几个方式哪个最快呢,今天就来稍微测试一下

普通方式请求百度5次

import socket
import time
import socks socks.set_default_proxy(socks.HTTP,addr='192.168.105.71',port=80) #设置socks代理
socket.socket = socks.socksocket # 把代理应用到socket
def blocking(wd):
sock = socket.socket()
sock.connect(('www.baidu.com',80)) # 连接百度
request = 'GET {} HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(wd)) # 构造http请求头
response = b'' # 用于接收数据
sock.send(request.encode()) # 发送http请求
chunk = sock.recv(1024) # 一次接收1024字节数据
while chunk: # 循环接收数据,若没有数据了说明已接收完
response += chunk # 字符串拼接
chunk = sock.recv(1024)
# print(response.decode())
return response def blocking_way():
search_list = ['python', 'java', 'C++', 'Ruby', 'Go']
for item in search_list:
blocking(item) if __name__ == '__main__':
start_time = time.time()
blocking_way()
print('请求5次百度总耗时:{}'.format(round(time.time()-start_time,2)))

多次执行结果:

请求5次百度总耗时:4.24秒

多线程版本

import socket
import time
import socks
from multiprocessing.pool import ThreadPool socks.set_default_proxy(socks.HTTP,addr='192.168.105.71',port=80) #设置socks代理
socket.socket = socks.socksocket # 把代理应用到socket
def blocking(wd):
sock = socket.socket()
sock.connect(('www.baidu.com',80)) # 连接百度
request = 'GET {} HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(wd)) # 构造http请求头
response = b'' # 用于接收数据
sock.send(request.encode()) # 发送http请求
chunk = sock.recv(1024) # 一次接收1024字节数据
while chunk: # 循环接收数据,若没有数据了说明已接收完
response += chunk # 字符串拼接
chunk = sock.recv(1024)
# print(response.decode())
return response def blocking_way():
#多线程
pool = ThreadPool(5) #实例线程池,开启5个线程
search_list = ['python','java','C++','Ruby','Go']
for i in search_list:
pool.apply_async(blocking,args=(i,)) # 提交任务到线程池
pool.close() #线程池不再接收任务
pool.join() #等待任务执行完 if __name__ == '__main__':
start_time = time.time()
blocking_way()
print('请求5次百度总耗时:{}'.format(round(time.time()-start_time,2)))

多次执行结果:

请求5次百度总耗时:1.0秒

多进程版本

import socket
import time
import socks
from multiprocessing import Pool socks.set_default_proxy(socks.HTTP,addr='192.168.105.71',port=80) #设置socks代理
socket.socket = socks.socksocket # 把代理应用到socket
def blocking(wd):
sock = socket.socket()
sock.connect(('www.baidu.com',80)) # 连接百度
request = 'GET {} HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(wd)) # 构造http请求头
response = b'' # 用于接收数据
sock.send(request.encode()) # 发送http请求
chunk = sock.recv(1024) # 一次接收1024字节数据
while chunk: # 循环接收数据,若没有数据了说明已接收完
response += chunk # 字符串拼接
chunk = sock.recv(1024)
# print(response.decode())
return response def blocking_way():
#多进程
pool = Pool(5)
search_list = ['python','java','C++','Ruby','Go']
for i in search_list:
pool.apply_async(blocking,args=(i,))
pool.close()
pool.join() if __name__ == '__main__':
start_time = time.time()
blocking_way()
print('请求5次百度总耗时:{}'.format(round(time.time()-start_time,2)))

多次执行结果:

请求5次百度总耗时:1.52秒

协程版本

from gevent import monkey;monkey.patch_socket()
import socket
import time
import socks
import gevent socks.set_default_proxy(socks.HTTP,addr='192.168.105.71',port=80) #设置socks代理
socket.socket = socks.socksocket # 把代理应用到socket
def blocking(wd):
sock = socket.socket()
sock.connect(('www.baidu.com',80)) # 连接百度
request = 'GET {} HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(wd)) # 构造http请求头
response = b'' # 用于接收数据
sock.send(request.encode()) # 发送http请求
chunk = sock.recv(1024) # 一次接收1024字节数据
while chunk: # 循环接收数据,若没有数据了说明已接收完
response += chunk # 字符串拼接
chunk = sock.recv(1024)
# print(response.decode())
return response def blocking_way():
search_list = ['python', 'java', 'C++', 'Ruby', 'Go']
tasks = [gevent.spawn(blocking,i) for i in search_list]
gevent.joinall(tasks) if __name__ == '__main__':
start_time = time.time()
blocking_way()
print('请求5次百度总耗时:{}'.format(round(time.time()-start_time,2)))

多次执行结果:

请求5次百度总耗时:1.02秒

IO多路复用版本

import socks
import time
import socket
import selectors
socks.set_default_proxy(socks.HTTP,addr='192.168.105.71',port=80) # 设置socks代理
socket.socket = socks.socksocket # 把代理应用到socket selector = selectors.DefaultSelector() # 事件选择器
flag = True # 事件循环的标志
times = 5 # 用于计数,每请求一次百度,就减1,若为0,说明已请求5次,此时结束事件循环 class Crawler():
def __init__(self,wd):
self.response = b'' # 用于接收数据
self.wd = wd # 搜索内容 def fetch(self):
'''创建客户端套接字,连接百度,定义好如果连接成功应该调用什么函数'''
client = socket.socket()
client.setblocking(False)
try:
client.connect(('www.baidu.com',80)) #此处需要注册事件监控
except BlockingIOError:
pass
selector.register(client,selectors.EVENT_WRITE,self.send_request) def send_request(self,client):
'''连接成功后发送请求到百度,并注册事件:收到百度应答应该做什么'''
selector.unregister(client) # 把原先监控的事件取消,方便后面监控其他事件
request = 'GET {} HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n'.format('/s?wd={}'.format(self.wd)) # 构造http请求头
client.send(request.encode())
selector.register(client,selectors.EVENT_READ,self.get_response) #此处注册事件,若百度响应,调用get_response def get_response(self,client):
'''若有数据发过来,就接收,每次发数据过来,都会触发,所以不用while循环'''
global flag
global times
data = client.recv(1024) # 每次接收的数据不超过1024字节,若大于1024,分批传输
if data:
self.response += data # 字符串拼接
else: # 数据接收完
# print(self.response.decode())
client.close()
selector.unregister(client)
times -= 1 # 每次请求的响应接收完后,计数器减一
if times == 0: # 5次请求完后,结束事件监控循环
flag = False
def loop():
'''事件监控循环'''
while flag:
events = selector.select()
for key,mask in events:
callback = key.data
callback(key.fileobj) if __name__ == '__main__':
start_time = time.time()
search_list = ['python', 'java', 'C++', 'Ruby', 'Go']
for item in search_list:
crawler = Crawler(item)
crawler.fetch()
loop()
print('请求5次百度耗时:{}'.format(round(time.time()-start_time,2)))

多次执行结果:

请求5次百度耗时:1.17秒

大家可以把请求数调多一些多试几次!

基本上协程和多线程耗时较短,更适用于爬虫。

多线程、多进程、协程、IO多路复用请求百度的更多相关文章

  1. 协程IO多路复用

    协程:单线程下实现并发并发:伪并行,遇到IO就切换,单核下多个任务之间切换执行,给你的效果就是貌似你的几个程序在同时执行.提高效率任务切换 + 保存状态并行:多核cpu,真正的同时执行串行:一个任务执 ...

  2. day 35 协程 IO多路复用

    0.基于socket发送Http请求 import socket import requests # 方式一 ret = requests.get('https://www.baidu.com/s?w ...

  3. 多线程 多进程 协程 Queue(爬虫代码)

    快速理解多进程与多线程以及协程的使用场合和特点 首先我们来了解下python中的进程,线程以及协程! 从计算机硬件角度: 计算机的核心是CPU,承担了所有的计算任务.一个CPU,在一个时间切片里只能运 ...

  4. Python之路--协程/IO多路复用

    引子: 之前学习过了,线程,进程的概念,知道了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位.按道理来说我们已经算是把CPU的利用率提高很多了.但是我们知道无论是创建多进程还是创建多 ...

  5. 12_进程,线程,协程,IO多路复用的区别

    1.进程 1.进程可以使用计算机多核 2.进程是资源分配的单位 3.进程的创建要比线程消耗更多的资源效率很低 4.进程空间独立,数据安全性跟好操作有专门的进程间通信方式 5.一个进程可以包含多个线程, ...

  6. 协程 IO多路复用

    -----------------------------------------------------------------试试并非受罪,问问并不吃亏.善于发问的人,知识丰富. # # ---- ...

  7. Python自动化 【第十篇】:Python进阶-多进程/协程/事件驱动与Select\Poll\Epoll异步IO

    本节内容: 多进程 协程 事件驱动与Select\Poll\Epoll异步IO   1.  多进程 启动多个进程 进程中启进程 父进程与子进程 进程间通信 不同进程间内存是不共享的,要想实现两个进程间 ...

  8. 也说性能测试,顺便说python的多进程+多线程、协程

    最近需要一个web系统进行接口性能测试,这里顺便说一下性能测试的步骤吧,大概如下 一.分析接口频率 根据系统的复杂程度,接口的数量有多有少,应该优先对那些频率高,数据库操作频繁的接口进行性能测试,所以 ...

  9. 深入浅析python中的多进程、多线程、协程

    深入浅析python中的多进程.多线程.协程 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源 ...

随机推荐

  1. ChemDraw绘制DNA结构的技巧

    对生物有一定了解的朋友都知道DNA是染色体的重要组成部分,DNA结构中包含重要的遗传物质,孩子的DNA来自父母DNA的组合,这就是为什么“一家人相像”的奥秘所在.ChemDraw虽然号称是化学结构绘制 ...

  2. 【SR】正则化超分辨率复原

    正则化超分辨率图像重建算法研究--中国科学技术大学 硕士学位论文--路庆春 最大后验概率(MAP)的含义就是在低分辨率图像序列已知的前提下,使高分辨率图像出现的概率达到最大.

  3. RPolar项目进度记录

    PolarMesDlg.cpp,中的 void PolarMesDlg::CImage2CImagedata(unsigned char* src,CImage* desimg,unsigned ch ...

  4. Oracle之完全卸载

    1. 开始->设置->控制面板->管理工具->服务 停止所有Oracle服务. 2. 开始->程序->Oracle - OraHome81->Oracle I ...

  5. 62、常规控件(5)Navigation View –美观的侧滑视图

    1.main_layout.xml <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.andr ...

  6. 将BT转为磁力链接

    实战代码 安装完成后,我们来看下代码: 系统环境:Linux Python环境:Python2.7 请注意python版本 bt2url.py 1 2 3 4 5 6 7 8 9 10 11 12 1 ...

  7. 数据库读写分离(aop方式完整实现)

    http://blog.csdn.net/machunlin2010/article/details/46471983

  8. 【BZOJ4550】小奇的博弈 博弈论

    [BZOJ4550]小奇的博弈 Description 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色.最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同.   小 ...

  9. 指定文件夹 指定文件后缀名 删除整个文件夹 git 冲突解决 create a new repository on the command line push an existing repository from the command line

    http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/001375840038939c2 ...

  10. 实践中需要了解的cpu特性

    目录 分段机制 特权级检查 GDT和LDT 堆栈切换 分页机制 中断 分段机制 实模式中cs是一个实实在在的段首地址,ip为cs所指向段的偏移,所以cs<<4+ip是当前cpu执行的指令. ...