- 高性能相关模块: - gevent # 源码用C实现 - twisted # 用的比较多,源码用python实现 - tornado # 源码用python实现 - ayncio # 源码用C实现 - 现象:一个线程实现并发请求 本质:socket+IO多路复用
问:10个URL,爬虫获取到数据?
url_list = [ 'http://www.cnblogs.com/xuyaping/p/7667055.html', 'http://www.baidu.com', 'http://www.xiaohuar.com', ] import requests # 1.串行(6s,用了一个线程或进程) for url in url_list: response = requests.get(url) print(response.content)
二、 线程、进程
# 2.线程,进程。耗费资源提高网络请求。(3s,用了3个线程或进程) # 不是创建越多的线程和进程就好,线程之间的切换耗时,效率很低。使用线程池 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor # ThreadPoolExecutor线程池,ProcessPoolExecutor进程池 # python2中没ThreadPoolExecutor线程池 def tast(url): response = requests.get(url) print(response.content) pool = ThreadPoolExecutor(10) #最多10个线程 # pool = ProcessPoolExecutor(10) # pool改为pool = ProcessPoolExecutor(10)就是进程池了 for url in url_list: pool.submit(tast,url) # tast为函数名,url为参数。去线程池中获取一个线程,执行tast函数 pool.shutdown(wait=True) # 等待上面的线程都执行完再往下走
三、 异步非阻塞
# 3.异步非阻塞的方式:本质是socket。 # 异步:回调,执行完后再回调这个函数。 # 非阻塞:不等。创建socket对象,连接,发送数据,接收数据一气呵成的,不等每个操作是否执行完毕。 # 阻塞:100个请求,向远程发连接,每个请求先执行connect,连接成功才能发送,连接的时候是堵塞的,第一个url连接,第二个等着第一个处理完。 # 并且第一个连接也要等着,等着发消息,等连接成功才能发消息,然后返回结果。 # client = socket();client.connet(ip,端口) # 非阻塞:第一个url来了,发连接,发过去不等,往下走要发送消息,但这时候发送消息可能会失败,因为可能还未连接成功,可能会报错,然后紧接着收消息,收不到报错。 # 所以单纯给socket设置上非阻塞一定会报错,所以这里非阻塞指的不是排队这个,而是一个url来了后是否阻塞。 # client = socket(); client.setblocking(False); client.connet(ip,端口) # 异步非阻塞的方式:100个url请求同时进行,先不发消息,全部只连接,当其中有url请求连接成功,告诉下我要发数据,这叫回调动作。收到回调动作后拿到结果再执行下一步操作。
a. asyncio
python3.3后增加的内置模块asyncio,但是该模块只能发tcp请求(socket的请求),不能发http请求,更偏向底层些。 也可以自己封装构造http请求。但不常用,太偏向底层。
import asyncio @asyncio.coroutine def fetch_async(host, url='/'): print(host, url) reader, writer = yield from asyncio.open_connection(host, 80) # open_connection,连接会阻塞,不等 # 发数据 request_header_content = """GET %s HTTP/1.0\r\nHost: %s\r\n\r\n""" % (url, host,) # GET %s HTTP/1.0\r\nHost: %s 构造请求头的一部分,\r\n\r\n 分割请求头请求体。封装成这种类型的发给TCP,TCP以为是http协议 request_header_content = bytes(request_header_content, encoding='utf-8') writer.write(request_header_content) yield from writer.drain() text = yield from reader.read() # 等待用户返回数据,等到返回结果后才往下走 print(host, url, text) writer.close() tasks = [ fetch_async('www.cnblogs.com', '/wupeiqi/'), fetch_async('dig.chouti.com', '/pic/show?nid=4073644713430508&lid=10273091') ] loop = asyncio.get_event_loop() results = loop.run_until_complete(asyncio.gather(*tasks)) loop.close()