4.28 笔记

昨日内容回顾

  • 死锁
'''
即使你知道如何抢锁释放锁    也很可能形成程序的死锁现象
后续咱们在写项目的时候    也不会本身去处理锁的问题    都是底层封装好的   因此你不用担忧
'''
  • 递归锁
# 他也是一把互斥锁,可是他能够被第一个抢到它的人连续的acquire和release
每一次acquire内部都有一个引用计数加一
每一次release内部都有一个引用计算减一
只要引用计数不为0   永远也没法被其余人抢到
  • 信号量
#信号量在不一样的领域和知识阶段可能对应不一样的概念
若是将互斥锁比喻成一个厕所,那么信号量就至关于多个厕所
  • event事件
一些线程/进程等待另外一些线程/进程发送能够运行的信号   才开始运行
from threading import Event
e = Event()

#等待
e.wait()
#发送信号
e.set()
  • 各类队列
常见队列   queue
先进先出
q = queue.Queue()
q.put()
q.get(timeout=3)
q.get_nowait()
q.full()
q.empty()
后进先出  LifoQueue()
q = queue.LifoQueue()
q.put()
q.get()
优先级	PriorityQueue()
q = queue.PriorityQueue()
q.put((10,"data"))
元组里面的第一个参数是数字,而且支持负数
数字越小优先级越高
  • 进程池线程池
硬件的发展确定是赶不上软件的开发速度
思考    咱们之前借助于开设进程和线程的方式来实现TCP服务端的并发     每来一个客户端就开设一个进程或线程

不管是开设进程仍是开设线程其实都会消耗必定的资源
咱们应该再保证计算机硬件安全的状况下,最大限度的利用计算机

池的概念
    它的出现是为了保证计算机硬件的安全
    下降了程序的运行效率   可是保证了计算机硬件安全
# 进程池线程池都不须要咱们本身去造,直接使用封装好的模块
from concurrent.future import ThreadPoolExecutor,ProcessPoolExecutor
# 生成进程池线程池
pool1 = ThreadPoolExecutor()    # 不默认是cpu个数的五倍
pool2 = ProcessPoolExecutor()    # 不默认是cpu个数
# 朝c池子中提交任务
pool1.submit(task,args...)    # 异步提交
res.result()   # 同步
# 池子对象的方法
pool1.shotdown()    # 关闭池子   等待池子中全部的任务运行结果   在继续日后执行代码

# 异步回调机制
给每个异步提交的任务绑定一个方法,一旦任务有结果了会自动触发该方法
pool1.submit(task,arge).add_done_callback(call_back)
#注意异步回调机制函数拿到的也是一个对象
  • 协程
单线程下实现并发
这个概念彻底是咱们程序员本身想出来的

多道技术
     切换+ 保存状态
咱们想经过代码层面本身检测IO行为,一旦有IO代码层面实现切换    这样给操做系统的感受好像我这个程序一直运行没有IO
欺骗操做系统从而最大化的利用cpu

一味的切换加保存状态也有可能会下降程序的效率
计算密集型    不行
io密集型     能够
  • gevent模块
# 该模块可以帮咱们检测IO并实现切换
# from gevent import monkey;monkey.patch_all()
from gevent import spawn

# spawn 在检测得时候   是异步提交的
spawn(server).join()
g = spawn(server)
q.join
  • 基于协程实现tcp服务端单线程下的并发
  • 总结
    • 多线程下面开设多线程,多线程下面利用协程,最大长度的提高软件的运行效率

IO模型简介

"""
咱们这里研究的IO模型都是针对网络IO的
Stevens在文章中一共比较了五种IO Model:
    * blocking IO           阻塞IO
    * nonblocking IO      非阻塞IO
    * IO multiplexing      IO多路复用
    * signal driven IO     信号驱动IO
    * asynchronous IO    异步IO
    由signal driven IO(信号驱动IO)在实际中并不经常使用,因此主要介绍其他四种IO Model。
"""
#1)等待数据准备 (Waiting for the data to be ready)
#2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)

同步异步
阻塞非阻塞
常见的网络阻塞状态:
  	accept
    recv
    recvfrom
    
    send虽然它也有io行为 可是不在咱们的考虑范围

阻塞IO模型

"""
咱们以前写的都是阻塞IO模型  协程除外
"""
import socket


server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)


while True:
    conn, addr = server.accept()
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:break
            print(data)
            conn.send(data.upper())
        except ConnectionResetError as e:
            break
    conn.close()
    
# 在服务端开设多进程或者多线程 进程池线程池 其实仍是没有解决IO问题	
该等的地方仍是得等 没有规避
只不过多我的等待的彼此互不干扰

非阻塞IO

"""
要本身实现一个非阻塞IO模型
"""
import socket
import time


server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)
server.setblocking(False)
# 将全部的网络阻塞变为非阻塞
r_list = []
del_list = []
while True:
    try:
        conn, addr = server.accept()
        r_list.append(conn)
    except BlockingIOError:
        # time.sleep(0.1)
        # print('列表的长度:',len(r_list))
        # print('作其余事')
        for conn in r_list:
            try:
                data = conn.recv(1024)  # 没有消息 报错
                if len(data) == 0:  # 客户端断开连接
                    conn.close()  # 关闭conn
                    # 将无用的conn从r_list删除
                    del_list.append(conn)
                    continue
                conn.send(data.upper())
            except BlockingIOError:
                continue
            except ConnectionResetError:
                conn.close()
                del_list.append(conn)
        # 挥手无用的连接
        for conn in del_list:
            r_list.remove(conn)
        del_list.clear()

# 客户端
import socket


client = socket.socket()
client.connect(('127.0.0.1',8081))


while True:
    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

总结python

"""
虽然非阻塞IO给你的感受很是的牛逼
可是该模型会	长时间占用着CPU而且不干活 让CPU不停的空转
咱们实际应用中也不会考虑使用非阻塞IO模型

任何的技术点都有它存在的意义 
实际应用或者是思想借鉴
"""

IO多路复用

"""
当监管的对象只有一个的时候 其实IO多路复用连阻塞IO都比比不上!!!
可是IO多路复用能够一次性监管不少个对象

server = socket.socket()
conn,addr = server.accept()

监管机制是操做系统自己就有的 若是你想要用该监管机制(select)
须要你导入对应的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)

总结linux

"""
监管机制其实有不少
select机制  windows linux都有

poll机制    只在linux有   poll和select均可以监管多个对象 可是poll监管的数量更多

上述select和poll机制其实都不是很完美 当监管的对象特别多的时候
可能会出现 极其大的延时响应

epoll机制   只在linux有
	它给每个监管对象都绑定一个回调机制
	一旦有响应 回调机制马上发起提醒

针对不一样的操做系统还须要考虑不一样检测机制 书写代码太多繁琐
有一我的可以根据你跑的平台的不一样自动帮你选择对应的监管机制
selectors模块
"""

异步IO

"""
异步IO模型是全部模型中效率最高的 也是使用最普遍的
相关的模块和框架
	模块:asyncio模块
	异步框架:sanic tronado twisted
		速度快!!!
"""
import threading
import asyncio


@asyncio.coroutine
def hello():
    print('hello world %s'%threading.current_thread())
    yield from asyncio.sleep(1)  # 换成真正的IO操做
    print('hello world %s' % threading.current_thread())


loop = asyncio.get_event_loop()
tasks = [hello(),hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

四个IO模型对比

参考博客园图解,稍微了解便可程序员

相关文章
相关标签/搜索