Python协程

协程的同步异步,数据传递,asyncio模块。


协程概念:

协程又称为为线程,纤程,是一种用户态的轻量级线程

发展历史:

    1.最初的生成器变形 yield/send

    2.引入@aysnico.coroutine和yield from

    3.在最近的python3.5版本中引入了async/await关键字

理解协程:

    1.普通理解:线程是系统级别的,他们是由操作系统调度。协程是程序级别的,他是由程序员根据需求自己调度,

我们把一些线程中的一个个函数称为子程序。那么子程序在执行的过程中可以中断去执行别的子程序,别的子程序也可以

中断回来继续执行之前的子程序,只就是协程。也就是说同一线程下的一段断码1执行着可以终端,然后去执行别的函数,

然后再回来执行代码块1,从中断的地方开始执行

    2.专业理解:协程拥有自己的寄存器,上下文和栈,协程在调度切换时,将寄存器上下文和栈保存到其他

的地方,在切回来时,恢复先前保存的寄存器上下文和栈。因此,协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。

优点:

    1、无需线程上下文切换的开销,(不需要调度时间)协程避免了无意义的调度,由此提高了性能,但是程序员那必须

自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力

    2、无需原子操作锁定及同步的开销

    3、方便控制流,简化编程模型

    4、高并发+高扩展性+低成本,一个CPU支持上万个协程不是问题。

缺点:

    1、无法调度多核资源,协程的本质是一个线程,它不能同时将单个CPU的多个核使用,协程需要和进程配合使用

才能运行在多CPU上,但是有一般不需要,除非是CPU密集型的应用。

    2、进行阻塞操作(耗时IO)会阻塞整个程序。

子程序:

在所有的语言中都是层级调度,比如A中调用B,B在执行过程中调用C,C执行完返回,B执行完返回,

最后是A执行完毕,是通过栈实现的,一个线程就是执行一个子程序,子程序的调用总是有一个入口,一次返回,调用

的顺序是明确的。

协程的数据传递:

.send

python 由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直被人诟病,在IO密集型的网络

编程里,异步处理比同步处理会提成上千倍。

同步:

只完成事物的路基,先执行第一个事物,如果阻塞了会一直等待,知道这个事物完成,在执行

第二个事物,顺序执行。

异步:

是和同步相对的,指在处理调用这个事物的之后,不会等待这个事物的处理结果,会直接会处

理结果,直接切处理第二个事物了,通过状态,通知,回调来通知调用者处理结果。

#同步代码

import time

def func():

    time.sleep(1)

for i in range(5):

    func()

    print(time.time())

#异步代码

import asyncio

async def func1():

    #模拟一个io操作

    asyncio.sleep(1)

    print(time.time(),"+++++++++++++")

loop = asyncio.get_event_loop()

for i in range(5):

    loop.run_until_complete(func1())

asyncio模块:

python 3.4版本引入的标准库,直接内置了对异步IO的支持

编程模式:

是有一个消息循环,我们从asyncio模式中直接换区一个EcentLoop的引用,然后把需要

执行的协程扔到EventLoop中执行,就实现了异步。

说明:

到目前为止实现协程的不仅只有asyncio,还有gevent 和tornado实现类似的功能

关键字说明:

    1、event_loop 事件循环:程序开启一个无线循环,把一些函数注册到事件循环中,当满足条件

发生时,调用相应的协程函数。

    2、coroutine 协程:协程对象,指一个使用了async关键字定义的函数,它的调用不会立即执行

函数,而是会返回一个协程对象,协程对象需要注册到事件循环中,由事件循环调用。

    3、task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步的封装,其中

包含了任务的各种状态,

    4、future :代表将来执行或没有执行的任务的结果,它和task没有本质上区别,

5、async/await:python3.5开始用于定义协程的关键字,async用于挂起阻塞异步调用接口,

 

#通过async生成协程对象,协程不能直接运行,需要将协程加入到事件循环中

async def run(x):

    print("waiting:%d"%x)

#得到一个协程对象,这个时候run()函数没有执行。

coroutine = run(2)

#引用一个时间循环(注意:真实情况实在asyncio模块中获取一个引用)

loop = asyncio.get_event_loop()

#协程对象加入到事件循环中,协程对象不能直接运行,在注册事件循环的时候,其实就是run_until_complete

#方法对协程对象包装哼了一个任务对象,task对象是Future类的子类,保存了协程运行后的状态,用于获取协程的结果

loop.run_until_complete(coroutine)

task 创建任务:

task = asyncio.ensure_future(coroutine)

#task = loop.create_task(coroutine)

loop.run_until_complete(task)

#future

#定义一个回调函数,参数为future,任务对象

并发和并行

并发:指多个任务需要同时进行,

并行:同一时刻有多个任务执行

并发类似一个老师在同一时间段辅导不同的人功课,

并行类似好几个老师同时辅导不同的人功课。

不同线程的事件循环

一般情况我们的事件循环用于注册协程,有一些协程需要动态的添加到事件循环中,简单的方式就是使用多线程,当前线程创建一个事件循环,然后开启一个新线程,在新线程中启动事件循环.当前线程不会被block

import asyncio

import threading

import time

def start_loop(lp):

    asyncio.set_event_loop(lp)

    lp.run_forever()

async def run(x):

    print("x:%d"%x)

    await asyncio.sleep(x)#模拟另一个协程

    print("finsish %d"%x)

start = time.time()

loop = asyncio.get_event_loop()

#创建新线程,用来启动事件循环,此时不会阻塞主线程

threading.Thread(target=start_loop, args=(loop,)).start()

end = time.time()

print("time:",end-start)

#给事件循环添加任务

# loop.call_soon_threadsafe(run, 4)

# loop.call_soon_threadsafe(run, 6)

asyncio.run_coroutine_threadsafe(run(4),loop)

asyncio.run_coroutine_threadsafe(run(6),loop)#这样就同步了.

#获取网页信息的协程练习.

#www.163.com  www.baidu.com  www.sohu.com  www.sina.com.cn

import asyncio

import time

import threading

def start_loop(lp):

    asyncio.set_event_loop(lp)

    lp.run_forever()

async  def weget(url):

    print("加载:",url)

    connect = asyncio.open_connection(url,443)

    reader,writer = await  connect  #挂起

    #连接成功

    header= "GET / HTTP/1.0\r\nHost: %s\r\n\r\n"%url

    writer.write(header.encode("utf-8"))

    await writer.drain()

loop = asyncio.get_event_loop()

#创建新线程,用来启动事件循环,此时不会阻塞主线程

threading.Thread(target=start_loop, args=(loop,)).start()

#给事件循环添加任务

for url in ["www.163.com", "www.baidu.com", "www.sohu.com", "www.sina.com.cn"]:

    asyncio.run_coroutine_threadsafe(weget(url), loop)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
协程(Coroutine)是一种用户态的轻量级线程,它可以在单个线程中实现多任务并发处理。Python中的协程通过生成器(generator)实现,使用yield语句来实现协程的暂停和恢复操作。 在Python 3.5之后,Python引入了async/await关键字,使得协程的使用更加方便和简洁。 下面是一个使用yield实现协程的示例: ```python def coroutine(): print("coroutine started") while True: value = yield print("Received value: ", value) c = coroutine() next(c) # 启动协程 c.send(1) # 发送值,并打印接收到的值 c.send(2) ``` 输出: ``` coroutine started Received value: 1 Received value: 2 ``` 在上面的代码中,使用yield语句实现了协程的暂停和恢复操作。在调用`c.send()`方法时,会将值发送给协程,并从yield语句处恢复协程的执行。协程会处理接收到的值,并在下一个yield语句处暂停,等待下一次发送。 除了使用yield语句来实现协程外,Python 3.5之后还可以使用async/await关键字来定义协程。使用async/await关键字定义的协程更加简洁和易于理解。下面是一个使用async/await关键字实现的协程示例: ```python async def coroutine(): print("coroutine started") while True: value = await asyncio.sleep(1) print("Received value: ", value) asyncio.run(coroutine()) ``` 在上面的代码中,使用async/await关键字定义了一个协程。使用`asyncio.sleep()`函数来实现协程的暂停操作,并在下一次事件循环时恢复协程的执行。使用`asyncio.run()`函数来运行协程。 总的来说,协程是一种非常有用的并发编程技术,可以在单个线程中实现高并发的处理。在Python中,可以使用生成器和async/await关键字来实现协程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值