• Day14


    本节内容:

    1:事件驱动模型 

    2:IO模型前戏准备

    3:4种IO模型

    1:事件驱动模型 

    传统的编程是如下线性模式的:

    开始--->代码块A--->代码块B--->代码块C--->代码块D--->......--->结束

    每一个代码块里是完成各种各样事情的代码,但编程者知道代码块A,B,C,D...的执行顺序,唯一能够改变这个流程的是数据。输入不同的数据,根据条件语句判断,流程或许就改为A--->C--->E...--->结束。每一次程序运行顺序或许都不同,但它的控制流程是由输入数据和你编写的程序决定的。如果你知道这个程序当前的运行状态(包括输入数据和程序本身),那你就知道接下来甚至一直到结束它的运行流程。

     对于事件驱动型程序模型,它的流程大致如下:

    开始--->初始化--->等待

     与上面传统编程模式不同,事件驱动程序在启动之后,就在那等待,等待什么呢?等待被事件触发。传统编程下也有“等待”的时候,比如在代码块D中,你定义了一个input(),需要用户输入数据。但这与下面的等待不同,传统编程的“等待”,比如input(),你作为程序编写者是知道或者强制用户输入某个东西的,或许是数字,或许是文件名称,如果用户输入错误,你还需要提醒他,并请他重新输入。事件驱动程序的等待则是完全不知道,也不强制用户输入或者干什么。只要某一事件发生,那程序就会做出相应的“反应”。这些事件包括:输入信息、鼠标、敲击键盘上某个键还有系统内部定时器触发。

    事件驱动模型在前端的时候会大量的使用这个概念。 

    事件驱动模型也是一种编程思想
    如 面向过程,面向对象 ,面向函数这些都是编程思想

    事件驱动的执行流程,

    • 1内部维护一个事件列表 ,
    • 2当发生一个事件就从列表appent一个事件,
    • 3 有一个线程一直从事件列表取事件,然后执行对应事件的函数

    2:IO模型前戏准备

    在进行解释之前,首先要说明几个概念:

    1. 用户空间和内核空间
    2. 进程切换
    3. 进程的阻塞
    4. 文件描述符
    5. 缓存 I/O

    3.IO模型

    一、阻塞IO模型

    在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:

    解析:当socket—server应用程序发送accept进行了系统调用就一直阻塞住整个程序,直到有人链接为止。

    大白话 :
    阻塞IO 去车站买票一直排队阻塞,直到买到票为止

    ##########server############
    import  socket 
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',8001))
    sk.listen(5)
    
    while 1 :
        conn,addr = sk.accept()   ##阻塞住
        while 1 :
            data = conn.recv(1024)  ##阻塞住
            
    ##########client#########
    
    import  socket 
    cs = socket.socket()
    cs.connect(('127.0.0.1',8001))
    while 1:
        data = input('plz input something:')
        cs.send(b'%s'%data)

    二、 non-blocking IO(非阻塞IO)

    linux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:

    大白话:

    非阻塞IO  去车站买票车站进行排号,每隔一段时间回来看是不是轮到自己了,每一次间隔的时间就可以去做其他的事情了。
    存在缺点:

    • 每一次去内存看数据是否存在,发了太多的系统调用了
    • 数据没有实时。
    import time
    import socket
    sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sk.setsockopt
    sk.bind(('127.0.0.1',6667))
    sk.listen(5)
    sk.setblocking(False)   ##通过设置setblocking(False)就不会进行阻塞,去执行下面的else代码
    while True:
        try:
            print ('waiting client connection .......')
            connection,address = sk.accept()   # 进程主动轮询
            print("+++",address)
            client_messge = connection.recv(1024)
            print(str(client_messge,'utf8'))
            connection.close()
        except Exception as e:
            print (e)
            time.sleep(4)
    
    #############################client
    
    import time
    import socket
    sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    while True:
        sk.connect(('127.0.0.1',6667))
        print("hello")
        sk.sendall(bytes("hello","utf8"))
        time.sleep(2)
        break

    三、IO multiplexing(IO多路复用)

     IO多路复用有三种实现方式:优势 同时可以监听多个对象 

    1. select 
    2. poll
    3. epoll

    流程是这个样子:

    #***********************server.py
    import socket
    import select
    sk=socket.socket()
    sk.bind(("127.0.0.1",8801))
    sk.listen(5)
    inputs=[sk,]
    while True:
        r,w,e=select.select(inputs,[],[],5)
        print(len(r))
    
        for obj in r:
            if obj==sk:
                conn,add=obj.accept()
                print(conn)
                inputs.append(conn)
            else:
                data_byte=obj.recv(1024)
                print(str(data_byte,'utf8'))
                inp=input('回答%s号客户>>>'%inputs.index(obj))
                obj.sendall(bytes(inp,'utf8'))
    
        print('>>',r)
    
    #***********************client.py
    
    import socket
    sk=socket.socket()
    sk.connect(('127.0.0.1',8801))
    
    while True:
        inp=input(">>>>")
        sk.sendall(bytes(inp,"utf8"))
        data=sk.recv(1024)
        print(str(data,'utf8'))
    select的并发聊天

    r,w,e=select.select([sk,],[],[],5) ##四个参数分别是监听列表、输出列表、错误列表 5代表:就监听5秒钟,

    select和阻塞IO 一样都是去进行阻塞,不过阻塞的方式不一样,select可以阻塞并监听多个的对象,当对象发生变化的时候,
    对应的i 就是发生变化的对象,而且注意的select是通过水平触发的方式去发现对象是否改变。 

    三种多路复用的说明:

    select、poll、epoll 都是IO多路复用的实现,select在unix、windows、linux 都可以用。而windows只能用select  
    select监听的对象最大不能超过1024 个;
    而poll相当于是提高了监听的对象而已;
    而epoll 是根本上解决了;
    
    select 和 epoll 的大白话,
    select :考试结束交卷,要交卷拍一下桌子,而老师不知道到底是哪个 要交卷,就需要依次的遍历一个个的问过去。效率太低 
    epoll: 你们不管是谁要交卷,不要拍桌子了,你自报家门 说:我小虎要交卷,就直接找到了小虎收试卷。

    知识点:触发方式
    1:水平触发
    水平触发:也就是只有高电平(1)或低电平(0)时才触发通知,只要在这两种状态就能得到通知.
    上面提到的只要有数据可读(描述符就绪)那么水平触发的epoll就立即返回.


    2:边缘触发
    边缘触发:只有电平发生变化(高电平到低电平,或者低电平到高电平)的时候才触发通知.上面提到即使有数据
    可读,但是没有新的IO活动到来,epoll也不会立即返回.

    四、 Asynchronous I/O(异步IO)

    异步IO的最大特点就是全程无阻塞。

    linux下的asynchronous IO其实用得很少。先看一下它的流程:

    大白话:

    异步 就相当于你打了一个电话,说你要票,然后你就可以去干别的,直到系统打电话给你说 票到了,并把票送到你的手上。

    四种IO模型的比较:

    分析:

    阻塞IO全程都在阻塞;

    非阻塞IO只是在数据来了,才进行阻塞等待数据 ;

    IO多道模型,相当于也是阻塞的,只不过是select去阻塞,且可以进行监听多个的对象。 

    异步IO 全程没有一丝的阻塞。

  • 相关阅读:
    高性能IO模型浅析
    使用vbs脚本进行批量编码转换
    Linux模块机制浅析
    源文件移动后gdb不显示代码的原因
    Linux的原子操作与同步机制
    ARM的常数表达式
    安装卡巴 OFFICE链接 出现这个过程被中断,由于本机的限制
    selenium “could not be scrolled into view”
    bs4 FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?
    vim实现实时自动保存
  • 原文地址:https://www.cnblogs.com/hero799/p/8617229.html
Copyright © 2020-2023  润新知