欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

协程--Python

程序员文章站 2023-12-09 20:08:21
协程首先要了解两个概念上下文在每个任务运行前,CPU都需要知道任务从哪里加载,又是从哪里开始运行,也就是说,需要系统事先帮他设置好CPU寄存器和程序计数器(Program Counter,PC)CPU寄存器,是CPU内置的容量小、但速度极快的内存。程序计数器,则是用来存储CPU正在执行的指令的位置,或者即将执行的下一条指令的位置。他们都是CPU在运行任何任务前,必须依赖的环境,因此也被叫做CPU上下文。知道了什么是CPU上下文,也就很容易理解CPU上下文切换。CPU上下文切换,就是先把...

协程

首先要了解两个概念

  1. 上下文

    在每个任务运行前,CPU都需要知道任务从哪里加载,又是从哪里开始运 行,也就是说,需要系统事先帮他设置好CPU寄存器和程序计数器(Program Counter,PC)

    CPU寄存器,是CPU内置的容量小、但速度极快的内存。程序计数器,则是用来存储CPU正在执行的指令的位置,或者即将执行的下一条指令的位置。他们都是CPU在运行任何任务前,必须依赖的环境,因此也被叫做CPU上下文。

    知道了什么是CPU上下文,也就很容易理解CPU上下文切换。CPU上下文切换,就是先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文,到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务

  2. IO操作

    网络io: 获取或者上传网络数据(下载或者上传)

    磁盘io : 读取写入文件

    io操作比较耗时,如果程序io设计不好,非常影响性能

了解了上面两个概念 然后引入协程

  • 协程 又称 微线程,纤程

  • 协程的实际概念

    协程是python中实现多任务的一种方式,是比线程跟小的执行单元,
    因为它自带CPU上下文,会在合适的时机,把一个协程切换到另一个协程,所以它是有一个执行单元,并且这个过程中保存或恢复CPU上下文的程序还是可以运行。

    这个合适的时机很重要由开发者自己确定

  • 下面我们使用简单的方式实现协程

    import time
    
    def test1():
    	while True:
    		print("text1")
    		yield
    		# 一个耗时操作 合适的时机
    		time.sleep(0.5)
    def test2():
    	while True:
    		print("text2")
    		yield
    		# 一个耗时操作 合适的时机
    		time.sleep(0.5)
    
    t1 = test1()
    t2 = test2()
    while True:
    	next(t1)
    	next(t2)
    
    

    应该很容易看出这个运行结果, 如果不知道yield,可以先去去了解一下生成器这个概念。

    这个就是协程的简单实现,然而我们日常用的一般是已经封装好的

  • gevent
    除了gevent还有一个greenlet也实现了协程,但是他还是需要人工切换。
    gevent是一个可以自行切换任务的模块,它的原理是当一个程序遇到IO操作时,会切换协程,保证别的程序还能运行,而不是等待IO,从而浪费了等待的时间。

    简单实现

    import gevent
    
    
    def test1(n):
        for i in range(n):
            print('test1----', i)
    		# 模拟一个耗时操作 必须用gevent的sleep(1)
            gevent.sleep(1)
    
    
    t1 = gevent.spawn(test1, 5)
    t2 = gevent.spawn(test1, 5)
    t3 = gevent.spawn(test1, 5)
    
    t1.join()
    t2.join()
    t3.join()
    # 下面方式与上面相同
    #gevent.joinall([
    #	gevent.spawn(test1, 5),
    #	gevent.spawn(test1, 5),
    #	gevent.spawn(test1, 5)
    #])
    
    
    
    

    运行结果
    协程--Python
    具体运行效果建应自行尝试

一般情况下,为了避免阻塞自动切换协程,程序启动时要执行 monkey.patch_all()解决

import time

import gevent
from gevent import monkey

monkey.patch_all()


def test1(n):
    for i in range(n):
        print('test1----', i)
		# 因为 执行了 monkey.path_all() 所以当使用time来模拟耗时时也开始实现
        time.sleep(1)


gevent.joinall([
    gevent.spawn(test1, 5),
    gevent.spawn(test1, 5),
    gevent.spawn(test1, 5)
]
)

协程的大致情况就是如此,接下来我会在写一个用协程实现的并发下载器

相关标签: python 多线程