异步
- 一般代码是从上而下执行的,比如有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函数
用法:
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,且所有的任务都是一个进程执行
例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也支持调度代码在将来的某个特定事件运行,从而支持一个协程等待另一个协程完成,以处理系统信号和识别其他一些事件。
gevent模块:创建协程对象
环境准备
安装 pip install gevent
gevent模块方法
Gevent协程对象的方法:
例:
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}')
结果: