Python进阶之异步编程的含义和使用方法

异步编程

异步编程-----> 异步I/O(AIO)-----> 协作式并发 -----> 提高了CPU的利用率 -----> 协程

  • 同步—> 排队 ----> 有顺序 ----> 阻塞和等待
  • 异步—> 不排队 ----> 没有顺序 ----> 不阻塞和不等待

要想了解异步编程的用法,首先得清楚迭代器和生成器

  • 迭代器(iterator):实现了迭代器协议的对象
    • 迭代器协议实际上是两个魔术方法:
    • _iter_
    • _next_
# 写一个迭代器获取到斐波那契数列:1 1 2 3 5 8 13 21 34 55 ......
class FibTier:

    def __init__(self, num):
        self.a, self.b = 0, 1
        self.count = 0  # 计数器
        self.num = num

    def __iter__(self):
        return self

    def __next__(self):
        if self.count < self.num:
            self.a, self.b = self.b, self.a + self.b  # 递推公式
            self.count += 1
            return self.a
        raise StopIteration()


fib_list = FibTier(20)
for value in fib_list:
    print(value)
  • 生成器 - 迭代器语法简化升级版

  • 生成器表达式

    • (num for num in range(1, 100, 2))

    • num_gen = ((num for num in range(1, 100, 2)))
      print(type(num_gen))  # 
      
    • def create_num_gen():

      ​ yield from range(1, 100, 2)

  • def fib(num):
        a, b = 0, 1
        for _ in range(num):
            a, b = b, a + b
            yield a    # 每循环一次就产出一个a的值给你
    
    
    fib_iter = fib(20)  # 此处调用函数不是拿到一个返回值,而是拿到一个生成器对象
    print(type(fib_iter))   # 
    for value in fib_iter:
        print(value)
    
  • 生成器在进行预激活之后就可以变成协程(异步编程)

1、异步编程的使用方法

  • 预激活方式:

    • 先调用生成器函数:gen = cal_avg_value()
    • next(gen)
    • gen.send(None)
  • def cal_avg_value():
        total, count, average = 0, 0, None
        while True:
            # yield: 1.产出 - 平均值; 2、让步 - 让出CPU给协作的子程序
            current_value = yield
            # yield可以表示产出也可以表示屈服和让步
            total += current_value
            count += 1
            average = total / count
            print(f'平均值:{average}')
        # 该循环是在和main函数协作,main函数结束,该循环也就结束
    
    
    gen = cal_avg_value()
    print(type(gen))
    
    
    def main():
        gen = cal_avg_value()
    # 接下来要对生成器对象进行预激活,使其变成一个协程,两种方法都可以
    #     next(gen)
        gen.send(None)
        # 激活后再上传数据给gen = cal_avg_value()
        gen.send(10)
        gen.send(20)
        gen.send(30)
    
    
    if __name__ == '__main__':
        main()
    

2、异步编程的作用

异步编程在使用时实现了协作式并发,能够大幅度的提升了CPU的利用率

  • 下面先来看看同步编程:在同步编程的时候,数字是一个一个的输出的,有顺序的输出,同时每个数字需要休眠一秒,所以一共会耗时10秒才会输出结束
def display(num):
    print(num)
    time.sleep(1)

for num in range(1, 11):
    display(num)
  • 异步编程:
    • python中可以直接导入模块asyncio,然后用async来修饰函数
    • 被async 修饰的函数是异步函数,调用异步函数不是直接得到返回值,而是创建一个协程对象(可以跟其他子程序相互协作的子程序)
    • 然后需要创建一个列表,通过推导式调用函数并往列表里面创建协程对象
    • 此时需要启动一个事件循环,将协程对象注册到事件循环上(注册之后才能协作)
    • 由于不能直接上传列表,只能接受协程对象,就可以利用wait将列表中的协程对象处理成一个Task对象,然后挂到事件循环上,相当于将10个协程对象都注册到了事件循环上
async def display(num):
    print(num)
    await asyncio.sleep(1)  # 等待休眠结束,在等待时会主动地让出CPU,让给其他子程序


# 调用异步函数不是得到返回值,而是得到一个协程对象
print(display(1))  # 
cos_list = [display(n) for n in range(1, 11)]
print(cos_list)  # 该列表里面创建了十个协程对象
# 此时需要启动一个事件循环,将协程对象注册到事件循环上(注册之后才能协作)
loop = asyncio.get_event_loop()  # 拿到一个系统默认的事件循环
# loop.run_until_complete(cos_list[0])
loop.run_until_complete(asyncio.wait(cos_list))
# 不能直接上传列表,只能接受协程对象,
# wait就可以将列表中的协程对象处理成一个Task对象,然后挂到事件循环上
# 相当于将10个协程对象都注册到了事件循环上
loop.close()  # 该循环必须关掉

你可能感兴趣的:(python初学,列表,python,生成器,java,os)