码迷,mamicode.com
首页 > 编程语言 > 详细

python全栈开发day36-IO多路复用

时间:2018-06-20 18:53:39      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:异步io   同步   ndt   window   hide   sock   lin   recvfrom   实现   

一、复习

  1、进程、线程、协程

    进程:是计算机中最小的资源分配单位,数据隔离,可以利用多核,数据不安全

               线程:是计算机中最小的CPU调度单位,数据共享,GIL,数据不安全

    协程:是线程的一部分,是由用户来调度,数据共享,数据安全

  2、同步、异步、阻塞、非阻塞

      异步:同时做不止一件事

      同步:事情一件做完接着下一件

      阻塞:recv\recvfrom\accept\sleep\input

      非阻塞:

二、IO多路复用

    IO操作:

      文件处理:文件处理,json.dump/load,input,print,logging

      网络操作:recv/send,resvfrom/sendto,accept/connect

    # recv 为什么要阻塞
      # 等待数据来到我Python程序的内存里

  1.阻塞IO:

      技术分享图片

      技术分享图片

 

 

  2.非阻塞IO:

      技术分享图片

      技术分享图片

       代码举例:

      

技术分享图片
# import time
import socket
sk = socket.socket()
sk.bind((127.0.0.1,9000))
sk.setblocking(False)
sk.listen()
conn_lst = []
del_lst = []
while True:
    try:
        conn,addr = sk.accept()   #--> 非阻塞,没有连接来就报错
        conn_lst.append(conn)
        print(conn)
    except BlockingIOError:
        for con in conn_lst:   # conn1,conn2,conn3
            try:
                con.send(bhello)
                try:
                    print(con.recv(1024))     # 非阻塞 没有消息来就报错
                except BlockingIOError:pass   # recv没有消息的报错
            except ConnectionResetError:      # send没有连接的报错
                con.close()
                del_lst.append(con)
        for con in del_lst:
            conn_lst.remove(con)
        del_lst.clear()

# 非阻塞的形式实现了并发的socket server
# 非阻塞的形式实现了并发的socket server,太耗cpu
# 没有数据来 的时候 程序的高速处理极大地占用了CPU资源
非阻塞IO-server
技术分享图片
import socket

sk = socket.socket()
sk.connect((127.0.0.1,9000))
while True:
    print(sk.recv(1024))
    sk.send(bbye)
sk.close()
非阻塞IOclient

 

 

  3.IO多路复用:

      技术分享图片

 

      

技术分享图片
import select
import socket

sk = socket.socket()
sk.bind((127.0.0.1,9000))
sk.setblocking(False)
sk.listen()

rlst = [sk]   # 监听的是对象的读操作
wlst = []   # 监听的是对象的写操作
xlst = []   # 监听的是对象的异常操作
while True:
    rl,wl,xl = select.select(rlst,wlst,xlst)  # [sk,conn]
    for obj in rl:    # [conn1,conn2]
        if obj == sk:
            conn,addr = sk.accept()   # 每次建立连接的时候conn
            rlst.append(conn)
        else:
            msg = obj.recv(1024)
            if msg == b‘‘:
                obj.close()
                rlst.remove(obj)
                continue
            print(msg)
            obj.send(bhello)

# socketserver
# TCP协议的并发操作 selectors + 多线程
多路复用IO-select-sever
技术分享图片
import socket

sk = socket.socket()
sk.connect((127.0.0.1,9000))
while True:
    sk.send(bwahaha)
    print(sk.recv(1024))
sk.close()

# IO多路复用的select的工作机制
# select windows  轮询
# poll   linux    轮询,poll能够监听的对象比select要多
# epoll  linux    不是采用轮询的方式,而是采用回调函数的形式
多路复用IO-select-client


# IO多路复用的select的工作机制
# select windows  轮询
# poll   linux    轮询,poll能够监听的对象比select要多
# epoll  linux    不是采用轮询的方式,而是采用回调函数的形式

跨平台或平台自适应IO多路复用:

技术分享图片
import selectors
import socket

sel = selectors.DefaultSelector()


def accept(obj,mask):
    """
     回调函数,当selectors实例感知有用户连接服务器时,就会回调该函数。
    :param obj:
    :param mask:
    :return:
    """
    conn,addr = obj.accept()
    sel.register(conn, selectors.EVENT_READ, read)  # 注册用户连接conn到selector监听列表中


def read(conn,mask):
    """
    回调函数,当selectors实例感知有用户发送数据时,就会回调该函数。
    :param conn:
    :param mask:
    :return:
    """
    try:
        data = conn.recv(1024)
        if not data:    # 为空则抛出异常由下边的异常处理语句处理
            raise Exception
        conn.send(data+_sb.encode(utf-8))
    except Exception as e:
        print(closing, conn)
        sel.unregister(conn)
        conn.close()


sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind((127.0.0.1, 9000))
sk.listen()
sk.setblocking(False)
sel.register(sk, selectors.EVENT_READ, accept)


while 1:
    events = sel.select()   # [sk,conn1,conn2...] 谁有新的数据就会返回谁
    for key, mask in events:
        callback = key.data  # 回到函数
        callback(key.fileobj, mask)     # 执行回调函数
selectors-server
技术分享图片
import socket
sk = socket.socket()
sk.connect((127.0.0.1,9000))
while 1:
    inp = input(>>>)
    sk.send(inp.encode(utf-8))
    print(sk.recv(1024).decode(utf-8))
selectors-client

 

  4.异步IO:

      技术分享图片

 

  5.各种IO对比:

      技术分享图片

 

python全栈开发day36-IO多路复用

标签:异步io   同步   ndt   window   hide   sock   lin   recvfrom   实现   

原文地址:https://www.cnblogs.com/wuchenggong/p/9204331.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!