笔记
昨日内容回顾:
线程的一些其他方法
事件
队列 : queue.Queue先进先出 先进后出 优先级的队列
线程池: map submit result shutdown(close+join) add_done_callback
GIL锁 :
协程:单线程下实现并发
什么并发
并行
串行
今天的内容
协程:gevent模块,遇到IO自动切换任务
给大家看一个线程下(也就是协程)来实现多个客户端聊天
IO多路复用:模型(解决问题的方案)
同步:一个任务提交以后,等待任务执行结束,才能继续下一个任务
异步:不需要等待任务执行结束,
阻塞:IO阻塞,程序卡住了
非阻塞:不阻塞
作业
阻塞IO模型实现socket通信
Select IO多路复用实现以下socket通信
明日预习内容
https://www.cnblogs.com/clschao/articles/9712056.html
明日默写:
GIL锁
线程池中的几种方法,每个方法干什么用的写一下
作业:
1 通过线程池写一个并发的爬虫的程序,需要应用回调函数
2 自行完成一个简单的socketserver,使用面向对象+多线程来实现
gevent使用
import gevent
from gevent import monkey
monkey.patch_all()
import time
def eat(name):
print('%s eat 1' %name)
# gevent.sleep(2)
time.sleep(2)
print('%s eat 2' %name)
def play(name):
print('%s play 1' %name)
# gevent.sleep(2)
time.sleep(2)
print('%s play 2' %name)
g1=gevent.spawn(eat,'egon') #异步执行这个eat任务,后面egon就是给他传的参数
g2=gevent.spawn(play,name='egon')
# g1.join()
# g2.join()
gevent.joinall([g1,g2])
print('主')
select多路复用示例
from socket import *
import select
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8093))
server.listen(5)
# 设置为非阻塞
server.setblocking(False)
print(server)
rlist = [server,] #
wlist = []
del_list = []
wdict = {}
while 1:
print('laikankan')
rl,wl,xl=select.select(rlist,wlist,[],)
# rl,wl,xl=select.select(rlist,wlist,[],0.5)
print('>>>>',rl)
print('.....',rlist)
for s in rl: #循环所有有动静的对象
if s == server:
conn,addr = s.accept()
print('来自%s:%s'%(addr[0],addr[1]))
rlist.append(conn)
else:
data = s.recv(1024)
if not data: #b''
s.close()
rlist.remove(s)
# wdict[s] = data.upper()
wlist.append(s)
print(data)
for w in wl:
w.send()
# for del_l in del_list:
select客户端
import socket
client=socket.socket()
client.connect(('127.0.0.1',8093))
while True:
msg=input('>>: ').strip()
if not msg:continue
client.send(msg.encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))
client.close()
完整版的非阻塞IO模型服务端
import socket
import time
server=socket.socket()
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('127.0.0.1',8083))
server.listen(5)
server.setblocking(False) #设置不阻塞
r_list=[] #用来存储所有来请求server端的conn连接
w_list={} #用来存储所有已经有了请求数据的conn的请求数据
while 1:
try:
conn,addr=server.accept() #不阻塞,会报错
r_list.append(conn) #为了将连接保存起来,不然下次循环的时候,上一次的连接就没有了
except BlockingIOError:
# 强调强调强调:!!!非阻塞IO的精髓在于完全没有阻塞!!!
# time.sleep(0.5) # 打开该行注释纯属为了方便查看效果
print('在做其他的事情')
# print('rlist: ',len(r_list))
# print('wlist: ',len(w_list))
# 遍历读列表,依次取出套接字读取内容
del_rlist=[] #用来存储删除的conn连接
for conn in r_list:
try:
data=conn.recv(1024) #不阻塞,会报错
if not data: #当一个客户端暴力关闭的时候,会一直接收b'',别忘了判断一下数据
conn.close()
del_rlist.append(conn)
continue
w_list[conn]=data.upper()
except BlockingIOError: # 没有收成功,则继续检索下一个套接字的接收
continue
except ConnectionResetError: # 当前套接字出异常,则关闭,然后加入删除列表,等待被清除
conn.close()
del_rlist.append(conn)
# 遍历写列表,依次取出套接字发送内容
del_wlist=[]
for conn,data in w_list.items():
try:
conn.send(data)
del_wlist.append(conn)
except BlockingIOError:
continue
# 清理无用的套接字,无需再监听它们的IO操作
for conn in del_rlist:
r_list.remove(conn)
#del_rlist.clear() #清空列表中保存的已经删除的内容
for conn in del_wlist:
w_list.pop(conn)
#del_wlist.clear()
阻塞IO
import socket
import time
server=socket.socket()
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('127.0.0.1',8083))
server.listen(5)
print('你看看卡在哪')
server.setblocking(False)
while 1:
try:
conn, addr = server.accept()
print('来自%s的链接请求'%addr)
except BlockingIOError:
print('去买点药')
time.sleep(0.1)
阻塞IO的socket客户端
import socket
import time
ip_port = ('127.0.0.1',8083)
client = socket.socket()
client.connect(ip_port)
while 1:
client.send(b'dayangge henweisuo ')
time.sleep(0.1)
阻塞IO的socket服务端
import socket
import time
server=socket.socket()
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('127.0.0.1',8083))
server.listen(5)
print('你看看卡在哪')
server.setblocking(False)
rlist = []
rl = []
while 1:
try:
conn, addr = server.accept()
print(addr)
rlist.append(conn)
print('来自%s:%s的链接请求'%(addr[0],addr[1]))
except BlockingIOError:
print('去买点药')
# time.sleep(0.1)
print('rlist',rlist,len(rlist))
for con in rlist:
try:
from_client_msg = con.recv(1024)
except BlockingIOError:
continue
except ConnectionResetError:
con.close()
rl.append(con)
print('>>>>',rl)
for remove_con in rl:
rlist.remove(remove_con)
rl.clear()