内容概览:
local的概念
IO模型
IO多路复用
简述进程,线程,协程的区别,以及应用场景
进程:
特点:
进程是计算机中最小的资源分配单位
进程和线程是包含的关系,每个进程至少含有一个线程
可以利用多核,进程之间的数据是隔离的
进程的创建,销毁,以及切换 时间开销比较大
随着开启数量的增加 给操作系统带来负担
场景:
适用于利用多核的,高计算型的,启动数量有限的程序,
线程:
特点:
线程是CPU调度的最小单位,线程的切换是由操作系统完成的
由于GIL锁,在Cpython解释器下不能利用多核,
线程之间数据是共享的
线程的创建,销毁,切换的时间开销比进程要小很多
随着开启数量的增加,也会给操作系统带来负担
场景:
高IO型的,调度是用户不能干预的,程序
部分协程现有的模块不能自动规避IO操作的程序,适合用线程
协程:
特点:
协程的切换是用户自定义的
不能利用多核,不会产生数据不安全,
多个任务之间的切换不依赖与操作系统,
无论开启多少个协程,都不会给操作系统增加负担
应用场景:
高IO型,用户可以自己控制切换的,
能否抢占CPU更多的资源取决于用户的切换策略
适合使用于利用协程模块来规避IO操作的程序
threading模块里面的local用法:
多个线之间使用threading.local对象
obj=threading.local()#在那个线程生成就属于哪个线程,线程与线程之间是隔离的
obj.name = name
obj.age = age
可以实现多个线程之间数据的隔离
import time import random from threading import local,Thread loc = local() def func2(): global loc print(loc.name,loc.age) def func(name,age): global loc loc.name =name loc.age = age time.sleep(random.random()) func2() Thread(target=func,args=('alex',40)).start() Thread(target=func,args=('bos_jin',38)).start()
bos_jin 38 alex 40
五种IO模型:
Richard Stevens在书中介绍了5种模型
UNIX® Network Programming Volume 1,
Third Edition: The Sockets Networking ”,6.2节“I/O Models ”,
blocking IO 阻塞IO
noblocking IO 非阻塞IO
IO multiplexing IO多路复用
signal driven IO信号驱动IO
asycchronous 异步IO
同步与异步的区别:
同步:
一键事情做完了再去做另一件事情
异步:
同时做多件事情
相对论 异步是一个相对的概念从宏观上来看,似乎同时完成了几件事情
阻塞:
sleep input join shutdown get acquire wait
accept recv recvrfrom
非阻塞:
setblocking(False)
阻塞的IO会经历两个阶段
数据等待阶段 wait for data
数据拷贝阶段 copy data
用非阻塞IO写一个并发的聊天:
server端:
import time import socket sk = socket.socket() sk.bind(('127.0.0.1',8989)) sk.setblocking(False)#非阻塞 sk.listen() conn_lsit = [] del_list = [] while True: try: conn,addr = sk.accept() conn_lsit.append(conn) except BlockingIOError: for conn in conn_lsit: try : conn.send(b'hello') print(conn.recv(1024)) except (NameError,BlockingIOError):pass except ConnectionResetError: conn.close() del_list.append(conn) for del_conn in del_list: conn_lsit.remove(del_conn) del_list.clear()
client端:
import socket sk = socket.socket() sk.connect(('127.0.0.1',8989)) while True: print(sk.recv(1024)) sk.send(b'bye')
总结一下:
非阻塞IO:
没有使用并发编程的机制 多进程 线程 进程池 线程池 协程
完全是一个同步的程序实现了非阻塞
整体思路:
程序不会再某一个recv accept上被阻塞
因此程序可以腾出更多的时间来进行其他的收发工作
利弊:
太多的while True循环 以及报错处理
CPU的高速运转 占用了大量的CPU资源 CPU资源被大量的浪费
IO多路复用 select模块
找了一个代理专门从事于消息的收发,来了信息则通知程序来copy数据
server端:
import select #用于对接 操作系统中的 select机制(多路复用) import socket sk = socket.socket() sk.bind(('127.0.0.1',8989)) sk.setblocking(False) sk.listen() r_lst = [sk,] while True: r_l,_,_ = select.select(r_lst,[],[])#r_lst作为监听的对象 for item in r_l: if item is sk: conn,addr = sk.accept() r_lst.append(conn) else: try: print(item.recv(1024)) item.send(b'hello') except ConnectionResetError: item.close() r_lst.remove(item)
client:
import socket sk = socket.socket() sk.connect(('127.0.0.1',8989)) while True: sk.send(b'bye') print(sk.recv(1024))
io多路复用的总结:
select模块:
运行平台:windows/mac/linux
底层是操作系统的轮询
有监听个数的限制
随着监听个数的增加 效率会降低
poll模块:
运行平台:mac/linux
底层是操作系统的轮询
有监听个数的限制,但是比select监听的个数多
随着监听个数的增加 效率会降低
epoll模块:
给每个监听的对象都绑定一个回调函数
不在受到监听个数的限制 效率不会受到影响