每日测验

  • 简述死锁现象

  • 你用过哪些队列

  • 阐述进程池线程池概念及基本使用

  • 什么是协程,如何简单实现

昨日内容回顾

  • 死锁现象
    ```python “”” 即便你知道如何抢锁释放锁 也极有可能造成程序的死锁现象

后续我们在写项目的时候 也不会自己去处理锁的问题 都是底层封装好的 所以你不用担心 “””

  1. - 递归锁
  2. ```python
  3. """
  4. 它也是一把互斥锁,但是它可以被第一个抢到它的人连续的acquire和release
  5. 每acquire一次内部有一个引用计数加1
  6. 每release一次内部有一个引用计数减1
  7. 只要引用计数不为0 永远也无法被其他人抢到
  8. """
  • 信号量

    1. """
    2. 信号量在不同的领域和知识阶段可能对应不同的概念
    3. 如果将互斥锁比喻成一个厕所 那么信号量就相当于多个厕所
    4. """
  • event事件
    ```python “”” 一些线程/进程等待另外一些线程/进程发送可以运行的信号 才开始运行 from threading import Event e = Event()

等待

e.wait()

发送信号

e.set() “””

  1. - 各种队列
  2. ```python
  3. """
  4. 1 常见队列 queue
  5. 先进先出
  6. q = queue.Queue()
  7. q.put()
  8. q.get(timeout=3)
  9. q.get_nowait()
  10. q.full()
  11. q.empty()
  12. 2 后进先出 LifoQueue()
  13. q = queue.LifoQueue()
  14. q.put()
  15. q.get()
  16. 3 优先级 PriorityQueue()
  17. q = queue.PriorityQueue()
  18. q.put((10,'data'))
  19. q.put((-5,'data'))
  20. 元祖里面的第一个参数是数字 并且支持负数
  21. 数字越小优先级越高
  22. """
  • 进程池线程池
    ```python “”” 硬件的发展肯定是赶不上软件的开发速度的

思考我们以前借助于开设进程和线程的方式来实现TCP服务端的并发 每来一个客户端就开设一个进程或者线程

无论是开设进程还是开设线程其实都需要消耗一定的资源

我们应该在保证计算机硬件安全的情况下,最大限度的利用计算机

池的概念 它的出现是为了保证计算机硬件的安全 降低了程序的运行效率 但是保证了计算机硬件安全 “””

进程池线程池都不需要我们自己去造 直接使用封装好的模块

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

1 生成进程池线程池

pool1 = ThreadPoolExecutor() # 不填默认是cpu个数的五倍 pool2 = ProcessPoolExecutor() # 不填默认就是cpu的个数

2 朝池子中提交任务

pool1.submit(task,args…) # 异步提交

3 submit其实会返回一个Future类的对象 该对象调用result就能获取到任务的结果

res = pool1.submit(task,args…) res.result() # 同步

4 池子对象的方法

pool1.shotdown() # 关闭池子 等待池子中所有的任务运行结束 再继续往后执行代码

5 异步回调机制

“””给每一个异步提交的任务绑定一个方法,一旦任务有结果了会立刻自动触发该方法””” pool1.submit(task,args).add_done_callback(call_back)

注意异步回调函数拿到的也是一个对象

  1. - 协程
  2. ```python
  3. """
  4. 单线程下实现并发
  5. 这个概念完全是我们程序员自己想出来
  6. 多道技术
  7. 切换+保存状态
  8. 我们想通过代码层面自己检测IO行为。一旦遇到IO代码层面实现切换
  9. 这样给操作系统的感觉好像我这个程序一直运行没有IO
  10. 欺骗操作系统从而最大化的利用CPU
  11. 一味的切换加保存状态也有可能会降低程序的效率
  12. 计算密集型的 不行
  13. IO密集型的 可以
  14. """
  • gevent模块
    ```python

    该模块能够帮我们检测IO并实现切换

    from gevent import monkey;monkey.patch_all() from gevent import spawn

spawn在检测的时候 是异步提交的

spawn(server).join() g = spawn(server) g.join

  1. - 基于协程实现TCP服务端单线程下的并发
  2. ```python
  3. # 代码稍微搂一眼 感受它的牛逼之处

总结

  1. """
  2. 多进程下面开设多线程
  3. 多线程下面再利用协程
  4. 最大长度的提升软件运行的效率
  5. """

今日内容概要

  • IO模型

  • 复习网络和并发知识点

  • 后期课程安排

IO模型简介

  1. """
  2. 我们这里研究的IO模型都是针对网络IO的
  3. Stevens在文章中一共比较了五种IO Model:
  4. * blocking IO 阻塞IO
  5. * nonblocking IO 非阻塞IO
  6. * IO multiplexing IO多路复用
  7. * signal driven IO 信号驱动IO
  8. * asynchronous IO 异步IO
  9. 由signal driven IO(信号驱动IO)在实际中并不常用,所以主要介绍其余四种IO Model。
  10. """
  11. #1)等待数据准备 (Waiting for the data to be ready)
  12. #2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
  13. 同步异步
  14. 阻塞非阻塞
  15. 常见的网络阻塞状态:
  16. accept
  17. recv
  18. recvfrom
  19. send虽然它也有io行为 但是不在我们的考虑范围

阻塞IO模型

image.png

  1. """
  2. 我们之前写的都是阻塞IO模型 协程除外
  3. """
  4. import socket
  5. server = socket.socket()
  6. server.bind(('127.0.0.1',8080))
  7. server.listen(5)
  8. while True:
  9. conn, addr = server.accept()
  10. while True:
  11. try:
  12. data = conn.recv(1024)
  13. if len(data) == 0:break
  14. print(data)
  15. conn.send(data.upper())
  16. except ConnectionResetError as e:
  17. break
  18. conn.close()
  19. # 在服务端开设多进程或者多线程 进程池线程池 其实还是没有解决IO问题
  20. 该等的地方还是得等 没有规避
  21. 只不过多个人等待的彼此互不干扰

非阻塞IO

image.png

  1. """
  2. 要自己实现一个非阻塞IO模型
  3. """
  4. import socket
  5. import time
  6. server = socket.socket()
  7. server.bind(('127.0.0.1', 8081))
  8. server.listen(5)
  9. server.setblocking(False)
  10. # 将所有的网络阻塞变为非阻塞
  11. r_list = []
  12. del_list = []
  13. while True:
  14. try:
  15. conn, addr = server.accept()
  16. r_list.append(conn)
  17. except BlockingIOError:
  18. # time.sleep(0.1)
  19. # print('列表的长度:',len(r_list))
  20. # print('做其他事')
  21. for conn in r_list:
  22. try:
  23. data = conn.recv(1024) # 没有消息 报错
  24. if len(data) == 0: # 客户端断开链接
  25. conn.close() # 关闭conn
  26. # 将无用的conn从r_list删除
  27. del_list.append(conn)
  28. continue
  29. conn.send(data.upper())
  30. except BlockingIOError:
  31. continue
  32. except ConnectionResetError:
  33. conn.close()
  34. del_list.append(conn)
  35. # 挥手无用的链接
  36. for conn in del_list:
  37. r_list.remove(conn)
  38. del_list.clear()
  39. # 客户端
  40. import socket
  41. client = socket.socket()
  42. client.connect(('127.0.0.1',8081))
  43. while True:
  44. client.send(b'hello world')
  45. data = client.recv(1024)
  46. print(data)

总结

  1. """
  2. 虽然非阻塞IO给你的感觉非常的牛逼
  3. 但是该模型会 长时间占用着CPU并且不干活 让CPU不停的空转
  4. 我们实际应用中也不会考虑使用非阻塞IO模型
  5. 任何的技术点都有它存在的意义
  6. 实际应用或者是思想借鉴
  7. """

IO多路复用

  1. """
  2. 当监管的对象只有一个的时候 其实IO多路复用连阻塞IO都比比不上!!!
  3. 但是IO多路复用可以一次性监管很多个对象
  4. server = socket.socket()
  5. conn,addr = server.accept()
  6. 监管机制是操作系统本身就有的 如果你想要用该监管机制(select)
  7. 需要你导入对应的select模块
  8. """
  9. import socket
  10. import select
  11. server = socket.socket()
  12. server.bind(('127.0.0.1',8080))
  13. server.listen(5)
  14. server.setblocking(False)
  15. read_list = [server]
  16. while True:
  17. r_list, w_list, x_list = select.select(read_list, [], [])
  18. """
  19. 帮你监管
  20. 一旦有人来了 立刻给你返回对应的监管对象
  21. """
  22. # print(res) # ([<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>], [], [])
  23. # print(server)
  24. # print(r_list)
  25. for i in r_list: #
  26. """针对不同的对象做不同的处理"""
  27. if i is server:
  28. conn, addr = i.accept()
  29. # 也应该添加到监管的队列中
  30. read_list.append(conn)
  31. else:
  32. res = i.recv(1024)
  33. if len(res) == 0:
  34. i.close()
  35. # 将无效的监管对象 移除
  36. read_list.remove(i)
  37. continue
  38. print(res)
  39. i.send(b'heiheiheiheihei')
  40. # 客户端
  41. import socket
  42. client = socket.socket()
  43. client.connect(('127.0.0.1',8080))
  44. while True:
  45. client.send(b'hello world')
  46. data = client.recv(1024)
  47. print(data)

总结

  1. """
  2. 监管机制其实有很多
  3. select机制 windows linux都有
  4. poll机制 只在linux有 poll和select都可以监管多个对象 但是poll监管的数量更多
  5. 上述select和poll机制其实都不是很完美 当监管的对象特别多的时候
  6. 可能会出现 极其大的延时响应
  7. epoll机制 只在linux有
  8. 它给每一个监管对象都绑定一个回调机制
  9. 一旦有响应 回调机制立刻发起提醒
  10. 针对不同的操作系统还需要考虑不同检测机制 书写代码太多繁琐
  11. 有一个人能够根据你跑的平台的不同自动帮你选择对应的监管机制
  12. selectors模块
  13. """

异步IO

  1. """
  2. 异步IO模型是所有模型中效率最高的 也是使用最广泛的
  3. 相关的模块和框架
  4. 模块:asyncio模块
  5. 异步框架:sanic tronado twisted
  6. 速度快!!!
  7. """
  8. import threading
  9. import asyncio
  10. @asyncio.coroutine
  11. def hello():
  12. print('hello world %s'%threading.current_thread())
  13. yield from asyncio.sleep(1) # 换成真正的IO操作
  14. print('hello world %s' % threading.current_thread())
  15. loop = asyncio.get_event_loop()
  16. tasks = [hello(),hello()]
  17. loop.run_until_complete(asyncio.wait(tasks))
  18. loop.close()

四个IO模型对比

参考博客园图解,稍微了解即可

网络并发知识点梳理

  • 软件开发架构
  • 互联网协议

    1. """
    2. osi七层
    3. 五层
    4. 每一层都是干嘛的
    5. 以太网协议 广播风暴
    6. IP协议
    7. TCP/UDP
    8. """
  • 三次握手四次挥手

  • socket简介
  • TCP黏包问题 定制固定长度的报头
  • UDP协议
  • socketserver模块
  • 操作系统发展史
  • 多道技术
  • 进程理论
  • 开启进程的两种方式
  • 互斥锁
  • 生产者消费者模型
  • 线程理论
  • 开启线程的两种方式
  • GIL全局解释器锁
  • 进程池线程池
  • 协程的概念
  • IO模型的了解