协程

协程

迭代器

  • 可迭代(Iterable):直接作用于for循环的变量
  • 迭代器(Iterator):不但可以作用于for循环,还可以被next调用
  • list是典型的可迭代对象,但不是迭代器
    • 通过instance判断
  • iterable和iterator可以转换
    • 通过iter函数
#可迭代
l = [i for i in range(10)]
for idx in l:
    print(idx)

# range是一个迭代器
for i in range(5):
    print(i)

0
1
2
3
4
5
6
7
8
9
0
1
2
3
4

# isinstance案例
#判断某个变量是否是一个实例

#判断是否可迭代
from collections import Iterable
l1 = [1,2,3,4,5]
print(isinstance(l1,Iterable))

from collections import Iterator
print(isinstance(l1,Iterator))

True
False

# iter函数
s = "come from ?"
print(isinstance(s,Iterable))
print(isinstance(s,Iterator))

s_iter = iter(s)
print(isinstance(s_iter,Iterable))
print(isinstance(s_iter,Iterator))

True
False
True
True`

生成器

  • generator: 一边循环一边计算下一个元素的机制/算法
  • 需要满足三个条件:
    • 每次调用都生产出for循环需要的下一个元素
    • 如果达到最后一个后,爆出StopIteration异常
    • 可以被next函数调用
  • 如何生成一个生成器
    • 直接使用
    • 如果函数中包含yield,则这个函数就叫生成器
    • next调用函数,遇到yield返回
#直接使用生成器
L = [x*x for x in range(5)]#放在中括号是列表生成器
g = (x*x for x in range(5))#放在小括号就是生成器
print(type(L))
print(type(g))

<class ‘list’>
<class ‘generator’>

# 函数案例
def odd():
        print("Step 1")
        print("Step 2")
        print("Step 3")
        return None
odd()


Step 1
Step 2
Step 3

# 生成器案例,yield负责返回
def odd():
        print("Step 1")
        yield 1
        print("Step 2")
        yield 2
        print("Step 3")
        yield 3
        return None
#odd()调用生成器
# 先生成一个生成器
g = odd()
one = next(g)
print(one)
two = next(g)
print(two)
three = next(g)
print(three)

Step 1
1
Step 2
2
Step 3
3

# for循环调用生成器
def fib(max):
    n,a,b = 0,0,1
    while n<max:
        print(b)
        a,b = b,a+b
        n+=1
    return "Done"
fib(5)

1
1
2
3
5
‘Done’

# 斐波那契数列的生成器写法
def fib(max):
    n,a,b = 0,0,1
    while n<max:
        yield b
        a,b = b,a+b
        n+=1
    return "Done"
g = fib(5)
for i in range(6):
    rst = next(g)
    print(rst)

1
3


StopIteration Traceback (most recent call last)
in
9 g = fib(5)
10 for i in g:
—> 11 rst = next(g)
12 print(rst)

StopIteration: Done

ge = fib(10)
'''
生成器的典型用法是在for中使用
比较常用的典型生成器就是range
'''
for i in ge:
    print(i)

1
1
2
3
5
8
13
21
34
55

协程

  • 历史历程
    • 3.4引入协程,用yield实现
    • 3.5引入协程语法
    • 实现的协程比较好的包有asyncio,tornado,gevent
  • 定义:协程 是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行程序
  • 从技术角度讲,协程就是一个你可以暂停执行的函数,或者把协程理解成生成器
  • 协程的实现
    • yield返回
    • send调用
# 协程代码案例1
def simple_coroutine():
    print("start")
    x = yield
    print("recived",x)
# 主线程
sc = simple_coroutine()
print(1111)
#可以使用sc.send(None),效果一样
next(sc) #预激

print(2222)
sc.send("zhexiao")

1111
start
2222
recived zhexiao


StopIteration Traceback (most recent call last)
in
11
12 print(2222)
—> 13 sc.send(“zhexiao”)

StopIteration:

协程的四个状态

- inspect.getgeneratorstate(...)函数确定,该函数会返回下述字符串中的一个:
    - GEN_CREATED:等待开始执行
    - GEN_RUNNING: 解释器正在执行
    - GEN_SUSPENED: 在yield表达式处暂停
    - GEN_CLOSED: 执行结束
    - next预激(prime)
# 协程的状态
def simple_coroutine(a):
    print("start")
    b = yield a
    print("recived",a,b)
    c = yield a+b
    print("recived",a,b,c)
# runc
sc = simple_coroutine(5)

aa = next(sc)
print(aa)
bb = sc.send(6)
print(bb)
cc = sc.send(7)
print(cc)

start
5
recived 5 6
11
recived 5 6 7


StopIteration Traceback (most recent call last)
in
13 bb = sc.send(6)
14 print(bb)
—> 15 cc = sc.send(7)
16 print(cc)

StopIteration:

协程终止

  • 协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的对象)
  • 终止协程的一种方式:发送某个哨兵值,让协程退出。内置的None 和 Ellipsis 等常量经常用作哨符值==。
  • yield from
    • 调用协程为了得到返回值,协程必须正常终止
    • 生成器正常终止会发出StopIteration异常,异常对象的value属性保存返回值
    • yield from从内部捕获StopIteration异常
    • 委派生成器
      • 包含yield from表达式的生成器函数
      • 委派生成器在yield from表达式出暂停,调用方可以直接把数据发给自生成器
      • 子生成器在把产出的值发给调用放
      • 子生成器在最后,解释器会抛出StopIteration,并且把返回值附加到异常对象上
def gen():
    for c in "AB":
        yield c
# list直接用生成器作为参数
print(list(gen()))

def gen_new():
    yield from "AB"
print(list(gen_new()))

[‘A’, ‘B’]
[‘A’, ‘B’]

asynsio

  • python3.4开始引入标准库当中,内置对异步io的支持
  • asyncio本身是一个消息循环
  • 步骤:
    • 创建消息循环
    • 把协程导入
    • 关闭
import threading
#引入异步io包
import asyncio

#使用协程
@asyncio.coroutine
def hello():
    print("Hello world! (%s)" % threading.currentThread())
    print("Start...(%s)" % threading.currentThread())
    yield from asyncio.sleep(5)
    print("Done...(%s)" % threading.currentThread())
    print("Hello again! (%s)" % threading.currentThread())
#启动消息循环
loop = asyncio.get_event_loop()
#定义任务
tasks = [hello(),hello()]
# asyncio使用wait等待他
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

RuntimeError: This event loop is already running

Hello world! (<_MainThread(MainThread, started 4924)>)
Start…(<_MainThread(MainThread, started 4924)>)
Hello world! (<_MainThread(MainThread, started 4924)>)
Start…(<_MainThread(MainThread, started 4924)>)
Done…(<_MainThread(MainThread, started 4924)>)
Hello again! (<_MainThread(MainThread, started 4924)>)
Done…(<_MainThread(MainThread, started 4924)>)
Hello again! (<_MainThread(MainThread, started 4924)>)

async and await

  • 为了更好的表示异步io
  • python3.5引入
  • 让协程代码更简洁
  • 使用上,可以简单的进行替换
    • 用async替换@asyncio.coroutine
    • await替换yield from
import threading
#引入异步io包
import asyncio

#使用协程
# @asyncio.coroutine
async def hello():
    print("Hello world! (%s)" % threading.currentThread())
    print("Start...(%s)" % threading.currentThread())
    await asyncio.sleep(15)
    print("Done...(%s)" % threading.currentThread())
    print("Hello again! (%s)" % threading.currentThread())
#启动消息循环
loop = asyncio.get_event_loop()
#定义任务
tasks = [hello(),hello()]
# asyncio使用wait等待他
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

RuntimeError: This event loop is already running

Hello world! (<_MainThread(MainThread, started 4924)>)
Start…(<_MainThread(MainThread, started 4924)>)
Hello world! (<_MainThread(MainThread, started 4924)>)
Start…(<_MainThread(MainThread, started 4924)>)
Done…(<_MainThread(MainThread, started 4924)>)
Hello again! (<_MainThread(MainThread, started 4924)>)
Done…(<_MainThread(MainThread, started 4924)>)
Hello again! (<_MainThread(MainThread, started 4924)>)

aiohttp

  • asyncio实现单线程的并发io,在客户端用处不大
  • 在服务器端可以asyncio+coroutine配合,因为http是io操作
  • asyncio实现了tcp,udp,ssl等协议
  • aiohttp是给予asyncio实现的http框架
  • pip install aiohttp
  • concurrent.futures

  • python3新增的库
  • 类似其他语言的线程池的概念
  • 利用multiprocessing实现真正的并行计算
  • 核心原理:以子进程的形式,并行运行多个python解释器,从而令python程序可以利用多核CPU来提升执行速度。
    • 由于子进程与主解释器相分离,所以他们的全局解释器锁也是相互独立的。
    • 每个子进程都能够完整的使用一个CPU内核。
    • concurrent.futures.Executor
      • ThreadPoolExecutor
      • ProcessPoolExecutor
      • 执行的时候需要自行选择
  • submit(fn,args,kwargs)
    • fn:异步执行的函数
    • args,kwargs参数
# 关于concurrent的案例
from concurrent.futures import ThreadPoolExecutor
import time

def return_future(msg):
    time.sleep(3)
    return msg

#创建一个线程池
pool = ThreadPoolExecutor(max_workers=2)

#往线程池加入2个task
f1 = pool.submit(return_future,'hello')
f2 = pool.submit(return_future,'world')

print(f1.done())
time.sleep(3)
print(f2.done())

print(f1.result())
print(f2.result())

False
True
hello
world

current中map函数

  • map(fn,*iterables,timeout=None)
    • 跟map函数类似
    • 函数需要异步执行
    • timeout:超时时间
import time,re
import os,datetime
from concurrent import futures
data = ['1','2']

def wait_on(argument):
    print(argument)
    time.sleep(2)
    return "ok"
ex = futures.ThreadPoolExecutor(max_workers=2)
for i in ex.map(wait_on,data):
    print(i)

1
2
ok
ok

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值