• 疫情环境下的网络学习笔记 python 4.28


    4.28

    昨日回顾

    • 死锁,递归锁

      递归锁:可以被第一个抢到的人连续acquire和release,锁内有一个引用计数

    • 信号量

    • event事件

      一些进程线程要等待别的地方发出信号才会继续运行

      from threading import event
      e = event()
      # 等待
      e.wait()
      # 发送信号
      e.set()
      
    • 各种队列

    • 进程池线程池

      池:保证计算机硬件的安全,降低了程序的运行效率

      使用池不需要自己造,直接使用封装好的模块

      from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
      # 生成池
      pool1 = ThreadPoolExecutor()
      pool2 = ProcessPoolExecutor()
      # 括号里面传数字,不传默认用计算机cpu核数
      # 基本使用,往池子里提交任务,异步得到结果
      pool1.submit(task,args).add_done_callback(callback)
      # 异步回调拿到的结果也是一个对象:future
      res.result() # 得到结果
      # 关闭池子
      pool1.shutdown()
      
    • 协程

      单线程下实现并发,使用gevent模块,在代码层面实现:io操作自动切换进程

      一味地切换保存状态也有可能降低效率:计算密集型程序

    • gevent模块

      from gevent import monkey;monkey.patch_all()
      from gevent import spawn
      # spawn在监测的时候是异步提交的
      spawn(server).join()
      
    • 基于协程实现tcp服务端,单线程的并发

    今日内容

    1. IO模型

    IO模型

    常见的网络罗阻塞状态

    • accept
    • recv
    • recvfrom

    send虽然也有io形为,但是不在我们的考虑范围内

    阻塞IO

    img

    我们之前写的都是阻塞IO模型,协程除外。在服务端开设多进程或着多线程,进程池线程池,只是多个人一起等待,该等的地方还是得等,没有解决io问题

    非阻塞IO

    img

    从图中可以看出,当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是用户就可以在本次到下次再发起read询问的时间间隔内做其他事情,或者直接再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存(这一阶段仍然是阻塞的),然后返回。

    ​ 也就是说非阻塞的recvform系统调用调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error。进程在返回之后,可以干点别的事情,然后再发起recvform系统调用。重复上面的过程,循环往复的进行recvform系统调用。这个过程通常被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,进行数据处理。需要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态。

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

    模型实现

    # 服务端
    import socket
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    server.setblocking(False)
    # 默认为True,改为False后将所有网络阻塞recv,accept变为非阻塞
    r_list = []
    del_list = []
    while True:
    	try:
    		conn,addr = server.accept()
    		r_list.append(conn)
    	except BlockIOError as e:
    		print('列表长度:',len(r_list))
    		# 对接收的每一个链接,依次接收消息
    		for conn in r_list:
    			try:
    				data = conn.recv(1024)
    				# 当前链接没有发送消息,查看下一个。。。
    				if len(data) == 0: # 客户端断开连接
    					conn.close() # 关闭conn
    					del_list.append(conn) # 将断开的链接从r_list中删除
    					continue
    			except BlockingIOError:
    				continue
    			except ConnectionResetError:
    				conn.close()
    				del_list.append(conn)
    		for conn in del_list:
    			r_list.remove(conn)
    			
    
    # 客户端
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    while True:
    	client.send(b'hello')
    	data = client.recv(1024)
    	
    

    虽然非阻塞模型可以实现无阻塞,但是这个模型会让cpu一直空转,实际应用中不会考虑使用非阻塞IO模型

    模型没有实际意义,是用于思想借鉴,搭建框架

    IO多路复用

    操作系统提供的监管机制,能够帮你监督socket对象和conn对象。只要有人触发了,立刻将对应的对象返回

    select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程

    当监管的对象只有一个的时候,IO多路复用的效率还比不上阻塞IO,但是多路复用可以一次监管多个对象

    监管机制是操作系统本身就有的,如果要用该监管机制,需要导入对应的模块(select)

    如何用

    import socket
    import select
    
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    server.setblocking(False)
    read_list = [server]
    
    
    while True:
        r_list, w_list, x_list = select.select(read_list, [], [])
        """
        帮你监管
        一旦有人来了 立刻给你返回对应的监管对象
        """
        # print(res)  # ([<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>], [], [])
        # print(server)
        # print(r_list)
        for i in r_list:  #
            """针对不同的对象做不同的处理"""
            if i is server:
                conn, addr = i.accept()
                # 也应该添加到监管的队列中
                read_list.append(conn)
            else:
                res = i.recv(1024)
                if len(res) == 0:
                    i.close()
                    # 将无效的监管对象 移除
                    read_list.remove(i)
                    continue
                print(res)
                i.send(b'heiheiheiheihei')
    
     # 客户端
    import socket
    
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    
    
    while True:
    
        client.send(b'hello world')
        data = client.recv(1024)
        print(data)
    

    总结:监管机制有很多,select,poll,epoll,等等机制

    select机制windows,Linux都有,poll机制只在linux有。poll和select都可以监管多个对象,但是poll监管的数量更多,select和poll机制都不是最完美的机制:当监管对象特别多的时候,会出现延时响应

    epoll:只在Linux有,给每一个监管对象都绑定一个回调机制,一旦有相应,惠帝啊机制立刻发起提醒

    针对不同的操作系统需要考虑不同的监测机制,写代码繁琐:可以使用selector模块,帮你针对不同的操作平台,选择不同的监管机制

    异步IO模型

    所有模型中效率最高,使用最广泛的,用于实现高并发,高速的场景

    img

    相关的模块和框架
    模块:asyncio
    框架:sanic,tronado,twisted
    速度快
    
    # asynico
    import asyncio,threading
    
    @asyncio.coroutine
    def hello():
    	print('hello',threading.current_thread())
    	yield from asyncio.sleep(1)
    	print
    

    四个IO模型对比

    img

    网络并发知识点梳理

    • 软件开发框架

    • 互联网协议

      osi七层,要知道每一层是干什么的,有什么协议
        - 以太网协议
        - IP协议
        - 。。。
      TCP/UDP协议 (重要)
        - 三次握手
        - 四次挥手
      
    • socket简介

    • TCP粘包问题

      自定义报头:字典
      struct模块
      
    • socketserver模块

    并发编程

    • 操作系统发展史
    • 进程理论
    • 开启进程的两种方式
    • 互斥锁
    • 生产者消费者模型
    • 线程理论
    • 开启线程的两种方式
    • GIL全局解释器锁
    • 进程池,线程池
    • 协程
    • IO模型

    下载MySql 5.6

  • 相关阅读:
    [LeetCode]题解(python):053-Maximum Subarray
    [LeetCode]题解(python):052-N-Queens II
    [LeetCode]题解(python):051-N-Queens
    [LeetCode]题解(python):050-Pow(x, n)
    [LeetCode]题解(python):049-Group Anagrams
    [LeetCode]题解(python):048-Rotate Image
    构建之法阅读笔记01
    软件工程第一周开课博客
    第二周作业:返回一个整数数组中最大子数组的和
    第二周javaweb学习进度表
  • 原文地址:https://www.cnblogs.com/telecasterfanclub/p/12795408.html
Copyright © 2020-2023  润新知