• 15 并发编程-(IO模型)


    一、IO模型介绍

    1、阻塞与非阻塞指的是程序的两种运行状态

    阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源

    非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种手段让程序即便是遇到IO操作也不会停在原地,执行其他操作,力求尽可能多的占有CPU

    2、同步与异步指的是提交任务的两种方式:

    同步调用:提交完任务后,就在原地等待,直到任务运行完毕后,拿到任务的返回值,才继续执行下一行代码

    异步调用:当进程执行到一个IO(等待外部数据)的时候,不需要等待,待数据接收成功后,再回来处理。

    1.io模型
    提交任务得方式:
        同步:提交完任务,等结果,执行下一个任务
        异步:提交完,接着执行,异步 + 回调  异步不等结果,提交完任务,任务执行完后,会自动触发回调函数
    同步不等于阻塞:
        阻塞:遇到io,自己不处理,os会抢走cpu ,解决办法:监测到io,gevent切换到其他任务,类似欺骗os
        非阻塞:cpu 运行
    IO分类:
        1.阻塞IO        blocking IO
        2.非阻塞IO      nonblocking IO
        3.IO多路复用    IO multiplexing
        4.信号驱动IO    signal driven IO     用得比较少 
        5.异步IO        asynchronous IO
    遇到IO: 卡
        网络IO: 原地阻塞
        1.server端什么样得操作属于IO行为     
            # accept recv send 阻塞操作   accept recv 明显得等  send 不会明显等,但是一种io行为  
        2.为什么IO行为会让有在原地等待的效果  
    
    
    3.非阻塞io:
    自己监测io 遇到io 就切 并且把 单线程得效率提到最高
    导致得问题:
        1.当有数据来得时候,cpu 在做其他得事情,不会立即响应
        2.服务端没有任何阻塞,说白了,就是死循环,cpu会一直运转,线程处于就绪状态,大量占用cpu ,做无用,这个线程会一直问cpu,有数据没,有数据没
    不推荐使用
    
    
    4.多路复用io:
        wait copy  还多了select  中间有个中介存在,帮问os 有没有数据
        但是如果中介 只有1个 效率不如 阻塞效率
        但是如果中介监测多个套接字 ,性能高就是:同时监测多个套接字问os系统好了没  就比阻塞io效率高
         监测套接字得io行为
        服务端得套接字有几类:server conn
    
        select 阻塞io 效率高
           比非阻塞io 效率也高 ,一直做无用
    
    总结:
       同时监测多个套接字
       列表 循环 慢 假设列表数据多,循环 效率低  监测套接字好没好 从头到尾 循环1遍
       select  列表循环  效率低
       poll   可接收得列表数据多 效率也不高
       epoll 效率最高得 异步操作 每个套接字身上绑定个回调函数,谁好了谁触发回调,(就不用去遍历了 效率低)
       epoll  windows 不支持
              linux 支持
       selectors 模块  自动根据操作系统选择
       poll
       epoll

    二、阻塞IO模型

    默认情况下,所有的socket都是blocking模型,

    实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。

    这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。

    blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。

    三、非阻塞IO模型

     

    在非阻塞式IO中,用户进程其实是需要不断的主动询问kernel数据准备好了没有。

    from socket import *
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1',8083))
    server.listen(5)
    server.setblocking(False)
    print('starting...')
    
    rlist=[]
    wlist=[]
    while True:
    
        try:
            conn, addr = server.accept()
            rlist.append(conn)
            print(rlist)
        except BlockingIOError:
            # print('干其他的活')
    
            #收消息
            del_rlist = []
            for conn in rlist:
                try:
                    data=conn.recv(1024)
                    if not data:
                        del_rlist.append(conn)
                        continue
                    wlist.append((conn,data.upper()))
                except BlockingIOError:
                    continue
                except Exception:
                    conn.close()
                    del_rlist.append(conn)
    
            #发消息
            del_wlist=[]
            for item in wlist:
                try:
                    conn=item[0]
                    data=item[1]
                    conn.send(data)
                    del_wlist.append(item)
                except BlockingIOError:
                    pass
    
            for item in del_wlist:
                wlist.remove(item)
    
            for conn in del_rlist:
                rlist.remove(conn)
    
    server.close()
    View Code

    四、多路复用IO模型

    五、异步IO模型

    六、各种IO模型对比

    七、了解selectors模块的使用

  • 相关阅读:
    oralce 11g data guard
    oracle的锁与并发机制
    10 个MySQL数据库备份教程推荐
    Linux环境下用exp备份Oracle数据表并导入的脚本
    使用Oracle 10g的Logminer挖掘日志
    ORACLE查询表最近更改的数据
    如何监控oracle的索引是否使用
    看 淡 一切 生 命 只 是 个 过 程
    Java数组声明、创建、初始化
    Linux建立FTP的方法
  • 原文地址:https://www.cnblogs.com/foremostxl/p/9738068.html
Copyright © 2020-2023  润新知