46.python之异步

异步

  • 一般代码是从上而下执行的,比如有3个打印语句,正常执行是从第一个到最后一个按照顺序打印出来,也就是后面的打印语句会等待前面的打印语句执行完后在执行,这个是同步执行,同步意味着有序执行;
  • 而异步就是,后面的打印语句不会等待前面的执行完后再执行,也就是说异步不会阻塞其他任务执行,异步意味着无序执行

异步与多线程多进程:

  • 异步是轻量级的线程,可以叫做协程
  • 多进程和多线程无法获取函数的返回值,但是异步可以获取函数的返回值,进程池和线程池可以说是有异步的效果,它们可以获取函数的返回值
  • 主进程是异步才可以使用
  • 异步更适合需要返回值的操作,比如文件读写使用
  • 多线程和多进程更适合不需要返回值的操作

async与await关键字

  • Python3.4后才有的
  • async 定义异步
  • await 执行异步

用法:

# 定义异步函数
async def test(a):
    return a
    
# 执行异步
async def t2():
    res = await test(1)

asyncio模块:

  • 调用异步模块执行
  • 内置了对异步IO的支持,用于处理异步IO
  • 提供了使用协程构建并发应用的工具
  • asyncio提供的框架以事件循环(event loop)为中心,程序开启一个无限的循环,程序会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数

asyncio调用async函数
46.python之异步_第1张图片

用法:

async def main():
    result = await asyncio.gather(a(),b()) 
    print(result)
    
if __name__ == '__main__':
    asyncio.run(main())

例1:非异步

import time
import os

def test1():
    for i in range(3):
        print(f'test1,i={i},进程号:{os.getpid()}')
        time.sleep(1)

def test2():
    for j in range(3):
        print(f'test2,j={j},进程号:{os.getpid()}')
        time.sleep(1)

if __name__ == '__main__':
    # 开始时间
    start_time = time.time()
    test1()
    test2()

    print(f'时间间隔:{time.time()-start_time},进程号:{os.getpid()}')

结果:

  • 按照顺序执行,间隔时间是6s,且所有的任务都是一个进程执行
    46.python之异步_第2张图片

例2:异步

import time
import os
import asyncio
import threading

# 定义异步函数
async def test1():
    for i in range(3):
        print(f'test1,i={i},进程号:{os.getpid()},线程名称是:{threading.current_thread().name}')
        # 注意这里的等待时间也要修改成异步
        # time.sleep是cpu阻塞,asyncio.sleep是当前业务阻塞
        await asyncio.sleep(1)
    return "test1"

async def test2():
    for j in range(3):
        print(f'test2,j={j},进程号:{os.getpid()},线程名称是:{threading.current_thread().name}')
        # 注意这里的等待时间也要修改
        await asyncio.sleep(1)
    return "test2"

# 定义主异步函数
async def main():
    # 批量执行异步函数
    result = await asyncio.gather(test1(), test2())
    # 打印函数的返回值
    print(f'函数返回值:{result},线程名称是:{threading.current_thread().name}')
    return '我是主函数'

if __name__ == '__main__':
    # 开始时间
    start_time = time.time()
    # 执行主异步函数
    ar = asyncio.run(main())
    print(f'{ar},线程名称是:{threading.current_thread().name}')

    print(f'时间间隔:{time.time()-start_time},进程号:{os.getpid()},线程名称是:{threading.current_thread().name}')

结果:

  • 2个函数异步执行,时间间隔是3s,进程号相同,有点类似多线程,不过都是一个线程执行的
  • 它使用一种单线程单进程的的方式实现并发,应用的各个部分彼此合作, 可以显示的切换任务,一般会在程序阻塞I/O操作的时候发生上下文切换如等待读写文件,或者请求网络。
  • 同时asyncio也支持调度代码在将来的某个特定事件运行,从而支持一个协程等待另一个协程完成,以处理系统信号和识别其他一些事件。
    46.python之异步_第3张图片

gevent模块:创建协程对象

环境准备

安装 pip install gevent

gevent模块方法
46.python之异步_第4张图片

Gevent协程对象的方法:
46.python之异步_第5张图片

例:

import time
import os
import gevent
import threading

def test1(count):
    for i in range(count):
        print(f'test1,i={i},进程号:{os.getpid()},线程名称是:{threading.current_thread().name}')
        # 注意这里的时间也要修改成异步
        gevent.sleep(1)
    return "test1"

def test2():
    for j in range(3):
        print(f'test2,j={j},进程号:{os.getpid()},线程名称是:{threading.current_thread().name}')
        # 注意这里的时间也要修改
        gevent.sleep(1)
    return "test2"

if __name__ == '__main__':
    # 开始时间
    start_time = time.time()

    # 创建协程对象
    g1 = gevent.spawn(test1, 3)
    g2 = gevent.spawn(test2)

    # 批量处理协程对象
    g_list = [g1, g2]
    result = gevent.joinall(g_list)

    # 打印异步函数的返回值
    # 方式1:
    print(f'test1函数返回值:{g1.get()}')
    # 方式2:
    print(result[0].value, result[1].value)

    print(f'时间间隔:{time.time()-start_time},进程号:{os.getpid()},线程名称是:{threading.current_thread().name}')

结果:
46.python之异步_第6张图片

你可能感兴趣的:(python)