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. Android中文件加密和解密的实现

    最近项目中需要用到加解密功能,言外之意就是不想让人家在反编译后通过不走心就能获取文件里一些看似有用的信息,但考虑到加解密的简单实现,这里并不使用AES或DES加解密 为了对android中assets ...

  2. JFinal免费公开课更新中

    价值千元的课程,免费报名学习,JFinal学院-小木 录制JFinal视频教程,JFinal核心已经周边涉及到微信小程序开发.数据库.前端实战等.

  3. ionic 2 起航 控件的使用 客户列表场景(四)

    接下来,我们的客户列表要怎么刷新数据呢? 我们不会安卓开发,不会ios开发,没关系,我们还有ionic 2.ionic 2的控件 Ion-refresher 轻松帮我们搞掂. <!--下拉刷新- ...

  4. Lucene-如何编写Lucene程序

    Lucene版本:7.1 使用Lucene的关键点 创建文档(Document),添加文件(Field),保存了原始数据信息: 把文档加入IndexWriter: 使用QueryParser.pars ...

  5. sudo的用法

    为了系统安全我们一般不直接使用root用户进行日常维护,sudo是临时提升root权限,有时执行一些命令或者更新没权限的文件时需要使用root,这个时候就需要sudo上场了 普通用户是没有sudo使用 ...

  6. 洛谷——普及练习场 普及组选手可冲刺训练,提高组选手亦可在此巩固基础。(Loading...)

    简单的模拟 关卡2-1,6 道题 开始普及组的训练!所谓模拟,就是直接根据题意编写,思维难度简单. //T1 铺地毯 #include <cstdio> #define N 10005 i ...

  7. [Git]使用Git上传本地项目,并同步到Github上

    第一步:先要在github.com中创建一个仓库(New Repository). 第二步,打开Git Bash ① git init [+仓库名]:初始化仓库,执行之后可以在指定的仓库存放地上面看到 ...

  8. 在.net平台上运行伪JAVA

    由于在一个项目局方要求使用JAVA平台, 而当前又都是.net平台的应用. 重新用JAVA开发工作量太大. 时间也来不及. 想到在.net中有url rewrite功能, 何不先"骗&quo ...

  9. 2018.2.28 PHP中使用jQuery+Ajax实现分页查询多功能如何操作

    PHP中使用jQuery+Ajax实现分页查询多功能如何操作 1.首先做主页Ajax_pag.php 代码如下 <!DOCTYPE html> <html> <head& ...

  10. atoi 函数实现

      要考虑的东西实在也挺多的.总结如下:   1 前面空格分隔符号的时候   2 第一个符号位处理+ -   3 遇到非数字字符退出   4 为正数的时候,大于INT_MAX上溢   5 为负数的时候 ...