一、IO多路复用
IO多路复用:检测多个socket是否已经发生变化(是否已经连接成功/是否已经获取数据)(可读/可写)import socketdef get_data(key): client = socket.socket() client.setblocking(False) #将原阻塞的位置变成非阻塞 try: client.connect(("www.baidu.com",80)) #因为没有等待所以会报错 except BlockingIOError as e: pass client.sendall(b"GET /s?wd=%s HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n" %key) data_list = [] while 1: data = client.recv(8096) if not data: break data_list.append(data) data = b"".join(data_list) print(data.decode("utf8"))key_list = ["alex","sb","db"]for item in key_list: get_data(item)
二、基于IO多路复用+socket实现并发请求
IO多路复用 socket非阻塞 基于事件循环实现的异步非阻塞框架 非阻塞:不等待 异步:执行完某个人物后自动调用我给他的函数。 Python中开源 基于事件循环实现的异步非阻塞框架 Twisted总结:
1. socket默认是否是阻塞的?阻塞体现在哪里? 是,connect、accept、recv 2. 如何让socket编程非阻塞? setblocking(False) 3. IO多路复用作用? 检测多个socket是否发生变化。 操作系统检测socket是否发生变化,有三种模式: select:最多1024个socket;循环去检测。 poll:不限制监听socket个数;循环去检测(水平触发)。 epoll:不限制监听socket个数;回调方式(边缘触发)。 Python模块: select.select select.epoll4. 提高并发方案:
- 多进程 - 多线程 - 异步非阻塞模块(Twisted) scrapy框架(单线程完成并发) 5. 什么是异步非阻塞? - 非阻塞,不等待。 比如创建socket对某个地址进行connect、获取接收数据recv时默认都会等待(连接成功或接收到数据),才执行后续操作。 如果设置setblocking(False),以上两个过程就不再等待,但是会报BlockingIOError的错误,只要捕获即可。 - 异步,通知,执行完成之后自动执行回调函数或自动执行某些操作(通知)。6. 什么是同步阻塞?
- 阻塞:等 - 同步:按照顺序逐步执行 key_list = ['alex','db','sb'] for item in key_list: ret = requests.get('https://www.baidu.com/s?wd=%s' %item) print(ret.text)7.概念
#以前v = [[11,22],[33,44],[55,66]] #每一个都有一个append方法for item in v: print(item.append(1))#以后class Foo(object): def __init__(self,data): self.data = data def append(self,ietm): self.data.appded(item)v = [[11,22],[33,44],[55,66]]for item in v: print(item.append(1))
三、协程
概念:
进程、操作系统中存在
线程、操作系统中存在
协程、是由程序员创造出来的一个不是真实存在的东西
协程:是微线程,是对一个线程进行分片,使得线程在代码块之间来回切回执行,而不是在原来逐行执行
import greenletdef f1(): print(11) gr2.switch() print(22) gr2.switch()def f2(): print(33) gr1.switch() print(44)#协程gr1gr1 = greenlet.greenlet(f1)#协程gr2gr2 = greenlet.greenlet(f2)gr1.switch()
注:单纯用协程无用
协程+遇到IO就切换,才真的有用 pip3 install gevent
import geventfrom gevent import monkeymonkey.patch_all()import requestsdef get_page1(url): ret = requests.get(url) print(url,ret.content)def get_page2(url): ret = requests.get(url) print(url,ret.content)def get_page3(url): ret = requests.get(url) print(url,ret.content)gevent.joinall([gevent.spawn(get_page1, 'https://www.python.org/'), gevent.spawn(get_page2, 'https://www.yahoo.com/'), gevent.spawn(get_page3, 'https://github.com/') ])
总结:
1什么是协程:
协程也可以成为微线程,基石开发者控制线程执行流程,控制先执行某段代码然后在切换到另外函数执行代码
2.协程可以提高并发么
协程自己本身无法实现并发(甚至性能会降低)
协程+IO切换性能提高
3.进程、线程、协程的区别
4.单线程提高并发:
协程+IO切换:gevent
基于事件循环的异步非阻塞框架:Twisted
twisted
from twisted.web.client import getPage, deferfrom twisted.internet import reactordef all_done(arg): reactor.stop()def callback(contents): print(contents)deferred_list = []url_list = ['http://www.bing.com', 'http://www.baidu.com', ]for url in url_list: deferred = getPage(bytes(url, encoding='utf8')) deferred.addCallback(callback) deferred_list.append(deferred)dlist = defer.DeferredList(deferred_list)dlist.addBoth(all_done)reactor.run()