协程概念
1.协程是单线程。
2.协程比线程轻量,在多任务并发场景下,多任务在单个线程中轮流切换使用CPU,比多线程效率高。
3.因为是单线程,所以不需要考虑线程安全问题。
4.因为是单线程,所以无法利用CPU多核优势,可以配合多进程利用CPU多核满足一些极限场景。
协程关键字
1.async关键字
用来修饰函数,使其成为一个coroutine(协程)对象
async def get_url(url): # 被async修饰过的函数就是个协程对象,不能用普通函数调用方式调用
print(threading.current_thread().ident, url) # 打印出线程ID
try:
resp = requests.get(url, timeout=1)
except(ReadTimeout,ConnectTimeout):
return 'ReadTimeout OR ConnectTimeout'
return resp
2.await关键字
- await用在修饰IO阻塞代码处,其只能修饰协程对象。
- 当阻塞代码运行完毕,await也起到获取其返回结果的作用
async def main(url):
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
r = await get_url(url) # await只能修饰协程对象
print(url, r)
return r
运行协程代码
1.获取事件循环
事件循环相当于开了一个线程,等待将并发的任务集塞到这个线程中执行
loop = asyncio.get_event_loop() # 获取事件循环
2.获取任务集
tasks = [main(url) for url in urls] # 生成协程作业列表
3.运行任务
resp = loop.run_until_complete(asyncio.gather(*tasks)) # asyncio.gather()将多个协程任务封装成一个协程任务供循环事件调用
print(resp) # resp是所有协程对象运行的返回结果,类型是列表
以下是完整代码
声明:这是我对asyncio的个人理解,错误之处欢迎批评指正,谢绝侮辱字眼。
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------------
# Name: asyncio
# Description:
# Author: CHEN
# Date: 2022/5/9
# -------------------------------------------------------------------------------
import requests
import threading
import asyncio
import time
from requests.exceptions import ReadTimeout,ConnectTimeout
# def run_time(func):
# def inner(*args, **kwargs):
# start = time.time()
# func(*args)
# print("RUN Time: {}s".format(int(time.time() - start)))
#
# return inner
async def get_url(url): # 被async修饰过的函数就是个协程对象,不能用普通函数调用方式调用
print(threading.current_thread().ident, url) # 打印出线程ID
try:
resp = requests.get(url, timeout=1)
except(ReadTimeout,ConnectTimeout):
return 'ReadTimeout OR ConnectTimeout'
return resp
async def main(url):
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
r = await get_url(url) # await只能修饰协程对象
print(url, r)
return r
if __name__ == '__main__':
# asyncio.run(main()) # Python3.7以上才能用这种调用方式
urls = ['https://www.baidu.com', 'https://github.com/', 'https://about.gitlab.com/']
loop = asyncio.get_event_loop() # 获取事件循环
tasks = [main(url) for url in urls] # 生成协程作业列表
resp = loop.run_until_complete(asyncio.gather(*tasks)) # asyncio.gather()将多个协程任务封装成一个协程任务供循环事件调用
print(resp) # resp是所有协程对象运行的返回结果,类型是列表