设计企业门户网站,叶县红色家园网站建设,给私人企业做网站推广,实木复合门网站建设价格一、协程1.1协程的概念协程#xff0c;又称微线程#xff0c;纤程。英文名Coroutine。一句话说明什么是线程#xff1a;协程是一种用户态的轻量级线程。#xff08;其实并没有说明白~#xff09;那么这么来理解协程比较容易#xff1a; 线程是系统级别的#xff0c;… 一、协程1.1协程的概念协程又称微线程纤程。英文名Coroutine。一句话说明什么是线程协程是一种用户态的轻量级线程。其实并没有说明白~那么这么来理解协程比较容易 线程是系统级别的它们是由操作系统调度协程是程序级别的由程序员根据需要自己调度。我们把一个线程中的一个个函数叫做子程序那么子程序在执行过程中可以中断去执行别的子程序别的子程序也可以中断回来继续执行之前的子程序这就是协程。也就是说同一线程下的一段代码执行着执行着就可以中断然后跳去执行另一段代码当再次回来执行代码块的时候接着从之前中断的地方开始执行。比较专业的理解是 协程拥有自己的寄存器上下文和栈。协程调度切换时将寄存器上下文和栈保存到其他地方在切回来的时候恢复先前保存的寄存器上下文和栈。因此协程能保留上一次调用时的状态即所有局部状态的一个特定组合每次过程重入时就相当于进入上一次调用的状态换种说法进入上一次离开时所处逻辑流的位置。1.2 协程的优缺点协程的优点 1无需线程上下文切换的开销协程避免了无意义的调度由此可以提高性能但也因此程序员必须自己承担调度的责任同时协程也失去了标准线程使用多CPU的能力 2无需原子操作锁定及同步的开销 3方便切换控制流简化编程模型 4高并发高扩展性低成本一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。协程的缺点 1无法利用多核资源协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要除非是cpu密集型应用。 2进行阻塞Blocking操作如IO时会阻塞掉整个程序2、Python中如何实现协程2.1 yield实现协程 前文所述“子程序函数在执行过程中可以中断去执行别的子程序别的子程序也可以中断回来继续执行之前的子程序”那么很容易想到Python的yield显然yield是可以实现这种切换的。def eater(name):print(%s eat food %name)while True:food yieldprint(done)
g eater(gangdan)
print(g)执行结果generator object eater at 0x0000000002140FC0由执行结果可以证明g现在就是生成器函数2.2 协程函数赋值过程用的是yield的表达式形式要先运行next()让函数初始化并停在yield然后再send() send会在触发下一次代码的执行时给yield赋值next()和send() 都是让函数在上次暂停的位置继续运行def creater(name):print(%s start to eat food %name)food_list []while True:food yield food_listprint(%s get %s ,to start eat %(name,food))food_list.append(food)
# 获取生成器
builder creater(tom)
# 现在是运行函数让函数初始化
next(builder)
print(builder.send(包子))
print(builder.send(骨头))
print(builder.send(菜汤))执行结果tom start to eat food
tom get 包子 ,to start eat
[包子]
tom get 骨头 ,to start eat
[包子, 骨头]
tom get 菜汤 ,to start eat
[包子, 骨头, 菜汤]需要注意的是每次都需要先运行next()函数让程序停留在yield位置。如果有多个这样的函数都需要执行next()函数让程序停留在yield位置。为了防止忘记初始化next操作需要用到装饰器来解决此问题def init(func):def wrapper(*args,**kwargs):builder func(*args,**kwargs)next(builder) # 这个地方是关键可以使用builder.send(None)第一次必须传入None。return builderreturn wrapper
init
def creater(name):print(%s start to eat food %name)food_list []while True:food yield food_listprint(%s get %s ,to start eat %(name,food))food_list.append(food)
# 获取生成器
builder creater(tom)
# 现在是直接运行函数无须再函数初始化
print(builder.send(包子))
print(builder.send(骨头))
print(builder.send(菜汤))执行结果tom start to eat food
tom get 包子 ,to start eat
[包子]
tom get 骨头 ,to start eat
[包子, 骨头]
tom get 菜汤 ,to start eat
[包子, 骨头, 菜汤]2.3 协程函数简单应用请给Tom投喂食物def init(func):def wrapper(*args,**kwargs):builder func(*args,**kwargs)next(builder)return builderreturn wrapper
init
def creater(name):print(%s start to eat food %name)food_list []while True:food yield food_listprint(%s get %s ,to start eat %(name,food))food_list.append(food)
def food():builder creater(Tom)while True:food input(请给Tom投喂食物).strip()if food q:print(投喂结束)return 0else:builder.send(food)
if __name__ __main__:food()执行结果Tom start to eat food
请给Tom投喂食物骨头
Tom get 骨头 ,to start eat
请给Tom投喂食物菜汤
Tom get 菜汤 ,to start eat
请给Tom投喂食物q
投喂结束2.4 协程函数的应用实现linux中grep -rl error 目录命令过滤一个文件下的子文件、字文件夹的内容中的相应的内容的功能程序首先了解一个OS模块中的walk方法,能够把参数中的路径下的文件夹打开并返回一个元组 import os # 导入模块os.walk(rE:\Python\script) #使用r 是让字符串中的符号没有特殊意义针对的是转义
generator object walk at 0x00000000035D3F10g os.walk(rE:\Python\script)next(g)
(E:\\Python\\script, [.idea, 函数], [])返回的是一个元组第一个元素是文件的路径第二个是文件夹第三个是该路径下的文件这里需要用到一个写程序的思想面向过程编程二、面向过程编程面向过程核心是过程二字过程及即解决问题的步骤基于面向过程设计程序就是一条工业流水线是一种机械式的思维方式。流水线式的编程思想在设计程序时需要把整个流程设计出来优点1体系结构更加清晰2简化程序的复杂度缺点可扩展性极其的差所以说面向过程的应用场景是不需要经常变化的软件如linux内核httpdgit等软件下面就根据面向过程的思想完成协程函数应用中的功能目录结构test
├── aa
│ ├── bb1
│ │ └── file2.txt
│ └── bb2
│ └── file3.txt
└─ file1.txt
文件内容
file1.txterror123
file2.txt123
file3.txt123error程序流程 第一阶段找到所有文件的绝对路径 第二阶段打开文件 第三阶段循环读取每一行 第四阶段过滤“error” 第五阶段打印该行属于的文件名第一阶段找到所有文件的绝对路径g是一个生成器就能够用next()执行每次next就是运行一次这里的运行结果是依次打开文件的路径 import osg os.walk(rE:\Python\script\函数\test)next(g)
(E:\\Python\\script\\函数\\test, [aa], [])next(g)
(E:\\Python\\script\\函数\\test\\aa, [bb1, bb2], [file1.txt])next(g)
(E:\\Python\\script\\函数\\test\\aa\\bb1, [], [file2.txt])next(g)
(E:\\Python\\script\\函数\\test\\aa\\bb2, [], [file3.txt])next(g)
Traceback (most recent call last):File input, line 1, in module
StopIteration我们在打开文件的时候需要找到文件的绝对路径现在可以通过字符串拼接的方法把第一部分和第三部分进行拼接用循环打开import os
dir_g os.walk(rE:\Python\script\函数\test)
for dir_path in dir_g:print(dir_path)结果(E:\\Python\\script\\函数\\test, [aa], [])
(E:\\Python\\script\\函数\\test\\aa, [bb1, bb2], [file1.txt])
(E:\\Python\\script\\函数\\test\\aa\\bb1, [], [file2.txt])
(E:\\Python\\script\\函数\\test\\aa\\bb2, [], [file3.txt])将查询出来的文件和路径进行拼接拼接成绝对路径import os
dir_g os.walk(rE:\Python\script\函数\test)
for dir_path in dir_g:for file in dir_path[2]:file %s\\%s %(dir_path[0],file)print(file)执行结果E:\Python\script\函数\test\aa\file1.txt
E:\Python\script\函数\test\aa\bb1\file2.txt
E:\Python\script\函数\test\aa\bb2\file3.txt用函数实现:import os
def search():while True:dir_name yielddir_g os.walk(dir_name)for dir_path in dir_g:for file in dir_path[2]:file %s\\%s %(dir_path[0],file)print(file)
g search()
next(g)
g.send(rE:\Python\script\函数\test)为了把结果返回给下一流程init # 初始化生成器
def search(target):while True:dir_name yielddir_g os.walk(dir_name)for pardir,_,files in dir_g:for file in files:abspath r%s\%s %(pardir,file)target.send(abspath)第二阶段打开文件init
def opener(target):while True:abspathyieldwith open(abspath,rb) as f:target.send((abspath,f))第三阶段循环读出每一行内容init
def cat(target):while True:abspath,fyield #(abspath,f)for line in f:restarget.send((abspath,line))if res:break第四阶段过滤init
def grep(pattern,target):tagFalsewhile True:abspath,lineyield tagtagFalseif pattern in line:target.send(abspath)tagTrue第五阶段打印该行属于的文件名init
def printer():while True:abspathyieldprint(abspath)
g search(opener(cat(grep(error.encode(utf-8), printer()))))
g.send(rE:\Python\script\函数\test)执行结果E:\Python\script\函数\test\aa\file1.txt
E:\Python\script\函数\test\aa\bb2\file3.txt 转载于:https://blog.51cto.com/xuanwei/1953449