038-2018-1030 gevent IO多路复用

笔记

 

昨日内容回顾:

 

线程的一些其他方法

事件

队列 : 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()


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值