1.协程(单线程实现并发)
2.I/0模型
2.1阻塞I/O
2.2非阻塞I/O

知识点一:协程
协程的目的:是想要在单线程下实现并发(并发看起来是同时运行的)
并发=多个任务间切换+保存状态(正常情况都是由操作系统来控制的)

一般情况下都是由操作系统来控制的,现在要实现的就是遇到I/o自己来切换,也叫并发

优点:在应用程序级别速度要远远高于操作系统的切换
缺点:多个任务一旦有一个阻塞没有切,整个线程都会阻塞原地,该线程内的其他任务
都不能执行

一旦引入协程,就需要检测单线程下所有的IO行为,实际遇到IO就切换,
少一个都不行,一旦一个任务阻塞了,整个线程就阻塞了,其他的任务即便是
可以计算,但是也无法运行了

一个程序没有遇到IO也切,反而会降低效率,应该找到一种让程序遇到IO切,才能提高效率

gevent模块:模拟识别IO阻塞
#gevent模块:模拟识别IO阻塞
import gevent
from gevent import monkey,spawn;monkey.patch_all() #pathch_all()打补丁就是让gevent能识别所有的IO
from threading import current_thread
import time def eat():
print('%s eat 1'%current_thread().name)
# gevent.sleep(2) #默认只能识别自己模块的Io行为
time.sleep(3)
print('%s eat 2'%current_thread().name) def play():
print('%s play 1'%current_thread().name)
# gevent.sleep(1)
time.sleep(1)
print('%s play 2'%current_thread().name) #创建协程对象
g1=spawn(eat,) #spawn(函数名,参数1...) 都是传给函数eat的
g2=spawn(play,) print(current_thread().name)
g1.join() #等待g1结束
g2.join() #等待g2结束 '''输出结果:
MainThread
DummyThread-1 eat 1 #假线程
DummyThread-2 play 1
DummyThread-2 play 2
DummyThread-1 eat 2 ''' '''
而time.sleep(2)或其他的阻塞,gevent是不能直接识别的需要用下面一行代码,打补丁,就可以识别了 from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前 或者我们干脆记忆成:要用gevent,需要将from gevent import monkey;monkey.patch_all()放到文件的开头

gevent应用实例一:利用gevent模块改写socket服务端实现:单线程IO切换自动切换

#服务端
from gevent import spawn,monkey;monkey.patch_all()
from socket import *
from threading import Thread def talk(conn):
while True:
try:
data=conn.recv(1024)
if len(data) == 0:break
conn.send(data.upper())
except ConnectionResetError:
break
conn.close() def server(ip,port,backlog=5):
server = socket(AF_INET, SOCK_STREAM)
server.bind((ip, port))
server.listen(backlog) print('starting...')
while True:
conn, addr = server.accept()
spawn(talk,conn) #原来造线程的方式:
# t = Thread(target=talk, args=(conn,))
# t.start() if __name__ == '__main__':
# server('127.0.0.1',8080)
g=spawn(server,'127.0.0.1',8080)
g.join() -------------------------------------------------------------------------------
#客户端
from socket import *
import os client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080)) while True:
msg='%s say hello' %os.getpid()
client.send(msg.encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))

知识点二:基于网络的IO模型
可以分为2大类:
第一类:
server.accept()
第二类:
conn.recv()
conn.send()

1.recv(收消息)
wait data:等待客户端产生数据--》客户端OS--》网络--》服务端操作系统缓存
copy data:由本地操作系统缓存中的数据拷贝到应用程序的内存中

2.send(发消息)
copy data

阻塞IO:blocking IO
blocking IO就是在执行的2个阶段(等待数据和拷贝数据两个阶段)都被block了

非阻塞IO:non-blocking IO:
思考:目的就是将将recv()阻塞的这个模型变为非阻塞,
即如果没有数据先执行其它的任务,并且最好在没有数据时客户端能返回一个
没有数据的提示信息

非阻塞IO:的问题
1.CPU占用率高(多数的询问是无用的)
2.for循环列表多的情况下会慢
3.数据得不到及时的处理(因为有时候存在可能刚切换到其他任务,数据就过来了
这样就不能及时处理)

非阻塞IO模型改写socket套接字服务端、客户端:

#服务端
from socket import *
import time server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False) #所有的IO行为都变为非阻塞模型,设置为False conn_l=[] #保存的是一堆连接,便于后面与每个客户端通信收发消息
while True:
#建立连接循环:
try:
print('总连接数[%s]' % len(conn_l))
conn,addr=server.accept()
conn_l.append(conn)
except BlockingIOError: #客户建立连接请求,报错信息,捕捉这个异常可以执行下面的代码,即执行其他任务
# print('客户端没有数据过来,可以执行其他任务')
del_l=[] #另外新建一个列表单独存放那些非法数据,方便最后清理这些数据 #建立通信循环:
for conn in conn_l:
try:
data=conn.recv(1024) #与accept()建立连接一样,如果没有消息过来,直接
if len(data) == 0: #输入的是空值
del_l.append(conn)
continue
conn.send(data.upper())
except BlockingIOError:
pass
except ConnectionResetError: #客户端单方面终止连接
del_l.append(conn) #将终止的连接添加到定义的列表里面,最后统一删除这些无效的连接 for conn in del_l:
conn_l.remove(conn) -----------------------------------------------------------------------------------------------------------------
#客户端:不需要变动
from socket import *
import os client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080)) while True:
msg='%s say hello' %os.getpid()
client.send(msg.encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))
 

Python 协程、IO模型的更多相关文章

  1. 协程 & IO模型 & HTTP协议

    今日内容 进程池与线程池的基本使用 协程理论与实操 IO模型 前端简介 内容详细 一.进程池与线程池的基本使用 1.进程池与线程池的作用 为了保证计算机硬件安全的前提下,提升程序的运行效率 2.回调机 ...

  2. 05网络并发 ( GIL+进程池与线程池+协程+IO模型 )

    目录 05 网络并发 05 网络并发

  3. 终结python协程----从yield到actor模型的实现

    把应用程序的代码分为多个代码块,正常情况代码自上而下顺序执行.如果代码块A运行过程中,能够切换执行代码块B,又能够从代码块B再切换回去继续执行代码块A,这就实现了协程 我们知道线程的调度(线程上下文切 ...

  4. day-5 python协程与I/O编程深入浅出

    基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1.  什么是协程(以下内容来自维基百 ...

  5. 协程IO多路复用

    协程:单线程下实现并发并发:伪并行,遇到IO就切换,单核下多个任务之间切换执行,给你的效果就是貌似你的几个程序在同时执行.提高效率任务切换 + 保存状态并行:多核cpu,真正的同时执行串行:一个任务执 ...

  6. [转载] Python协程从零开始到放弃

    Python协程从零开始到放弃 Web安全 作者:美丽联合安全MLSRC   2017-10-09  3,973   Author: lightless@Meili-inc Date: 2017100 ...

  7. python协程详解

    目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...

  8. Python协程与Go协程的区别二

    写在前面 世界是复杂的,每一种思想都是为了解决某些现实问题而简化成的模型,想解决就得先面对,面对就需要选择角度,角度决定了模型的质量, 喜欢此UP主汤质看本质的哲学科普,其中简洁又不失细节的介绍了人类 ...

  9. python 协程与go协程的区别

    进程.线程和协程 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定义: 操作系统能够进行运算调度的最小单位.它被包含在进 ...

  10. Python核心技术与实战——十六|Python协程

    我们在上一章将生成器的时候最后写了,在Python2中生成器还扮演了一个重要的角色——实现Python的协程.那什么是协程呢? 协程 协程是实现并发编程的一种方式.提到并发,肯很多人都会想到多线程/多 ...

随机推荐

  1. 大家一起和snailren学java-(序)

    由于最近在面试实习的时候,发现自己的java基础还是不是特别的扎实.因此再重新深入学习一下java.每天学习一点,都能进步一些. 用书<Thinking in java><effec ...

  2. HTML视频简介

    此文章复制原来文章,原网址是https://www.html5rocks.com/zh/tutorials/video/basics/#toc-encode 简介 视频标记是 HTML5 功能中备受关 ...

  3. 微软Bot Framework文档中,关于Sign-in Card的一处代码错误及更正

    Bot Framework文档出错处网址:https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.htm ...

  4. BZOJ 2119: 股市的预测 SA

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 434  Solved: 200[Submit][Status][Discuss ...

  5. (原)IPhone开发时把ToolBar中的元素居中的技巧

    在IPhone应用开发时,经常用到ToolBar,其中的控件通常都是居左,想让它居中就有点困难. 这里介绍一种方法: 将Flexible Space Bar Button Item从库中拖到位于控件左 ...

  6. 01_8_session

    01_8_session 1. session总结 1.1服务器的一块内存(存key-value) 1.2和客户端窗口对应(子窗口)(独一无二) 1.3客户端和服务器有对应的SessionID 1.4 ...

  7. Linux下手动备份还原硬盘主引导记录MBR跟硬盘分区表DPT教程

    Linux下手动备份还原硬盘主引导记录MBR跟硬盘分区表DPT教程 二 18 奶牛 Linux, Ubuntu, Windows 1,885 views查看评论 最近奶牛一直在折腾linux下的gru ...

  8. django logging日志优先级

    原创博文 转载请注明出处! 参考官方文档:https://docs.djangoproject.com/en/2.1/topics/logging/ Loggers¶ A logger is the ...

  9. PCA检测人脸的简单示例_matlab实现

    PCA检测人脸的简单示例,matlab R2009b上实现训练:训练用的20副人脸: %训练%Lx=X'*Xclear;clc;train_path='..\Data\TrainingSet\';ph ...

  10. Leetcode 20 有效的括号valid-parentheses(栈)

    给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空字符串可被认 ...