01、非阻塞IO完成http请求
--通过设置:
client.setblocking(False) # 设置不阻塞连接过程,直接设置会报错 -- BlockingIOError: [WinError 10035] 无法立即完成一个非阻止性套接字操作。
--在send recv函数上做错误处理OSError BlockingIOError,并不停循环。示例代码如下:
--这种方式属于IO非阻塞实现http请求
# 非阻塞IO带给我们的好处:通过非阻塞IO实现
import time
import socket
from urllib.parse import urlparse
def get_url(url):
# 解析出url
url = urlparse(url)
host = url.netloc
path = url.path
if path == "":
path = "/"
# 建立socket连接
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setblocking(False) # 设置不阻塞连接过程,直接设置会报错 -- BlockingIOError: [WinError 10035] 无法立即完成一个非阻止性套接字操作。
try: # 为了处理报错需要,try处理。但是仅仅try还是不行,需要查询是否连接完毕
client.connect((host, 80))
except BlockingIOError as e: # OSError: [WinError 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。
pass
# 不停轮询发送请求直至确认连接,这里send会抛OSError,recv会抛BlockingIOError
while True:
try:
client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8"))
print("send")
break
except OSError as e:
pass
# 接受请求
data = b""
while True:
try:
d = client.recv(1024)
print(d)
except BlockingIOError as e:
continue
if d:
data += d
else:
break
# 打印数据
data = data.decode("utf8")
html_data = data.split("\r\n\r\n")[1]
print(html_data)
client.close()
if __name__ == "__main__":
start_time = time.time()
url = "https://www.baidu.com/"
print(url)
get_url(url)
print(time.time() - start_time)
02、IO多路复用 -- select方式完成http请求
--select重新温习:
--import select包,系统自带。这个包不常用
--from selectors import DefaultSelector 使用这个包无需关心平台,且功能更加高级
--DefaultSelector 除了提供和IO复用的方法,还提供了注册的机制
--示例代码如下:
03、
04、回调的缺点
--回调将函数逻辑割裂
--回调的异常处理非常困难
--回调的多层嵌套:
--多层嵌套中有一层出现问题都会导致问题
--如果数据在多个嵌套中都需要被使用怎么办
--如何使用当前函数中的局部变量
05、什么是协程
高并发的实现原始方式有哪些痛点:
--回调模式代码编写复杂度高
--同步编程的并发性不高
--多线程的线程间同步使用lock机制,导致并发性能下降
--解决方案:
--采用同步的方式编写异步的代码
--是用单线程来切换任务
--线程是由操作系统切换的,单线程切换意味着需要程序员自己去调度任务
--不再需要锁,并发性高