关于异步IO这个概念,可能有些伙伴不是非常明白,那就先来看看异步IO是怎么回事儿。
为了大家能够更形象得理解这个概念,我们拿放羊来打个比方:

下载请求开始,就是放羊出去吃草;
下载任务完成,就是羊吃饱回羊圈。
同步放羊的过程就是这样的:
羊倌儿小同要放100只羊,他就先放一只羊出去吃草,等羊吃饱了回来在放第二只羊,等第二只羊吃饱了回来再放第三只羊出去吃草……这样放羊的羊倌儿实在是……

再看看异步放羊的过程:
羊倌儿小异也要放100只羊,他观察后发现,小同放羊的方法比较笨,他觉得草地一下能容下10只羊(带宽)吃草,所以它就一次放出去10只羊等它们回来,然后他还可以给羊剪剪羊毛。有的羊吃得快回来的早,他就把羊关到羊圈接着就再放出去几只,尽量保证草地上都有10只羊在吃草。

很明显,异步放羊的效率高多了。同样的,网络世界里也是异步的效率高。那么简单的异步程序怎么实现呢,请看接下来的示例源代码:

"""
desc:测试讲解python[版本3.8***]的异步[任务调度](https://zhida.zhihu.com/search?content_id=175153659&content_type=Article&match_order=1&q=%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6&zhida_source=entity)执行
欢迎添加qq群:492656241
针对内容:python、爬虫场景
"""
import asyncio
import time

task_count = 0  # 系统支持最大任务并发数
task_list = [{'name': 'task a', 'time': 1},
             {'name': 'task b', 'time': 2},
             {'name': 'task c', 'time': 3},
             {'name': 'task d', 'time': 4},
             {'name': 'task e', 'time': 5},
             {'name': 'task f', 'time': 6},
             {'name': 'task g', 'time': 7},
             {'name': 'task h', 'time': 8},
             {'name': 'task i', 'time': 9},
             {'name': 'task j', 'time': 10},
             {'name': 'task k', 'time': 11},
             {'name': 'task l', 'time': 12}]


async def delay_sleep(sleep_time):
    await asyncio.sleep(sleep_time)
    return sleep_time


async def request(unit):
    print("开始执行任务单元:", unit['name'])
    global task_count
    sleep_time = await delay_sleep(unit['time'])
    task_count -= 1  # 当前任务单元执行完成 系统正在执行任务数 -1
    print("任务单元执行完成:", unit['name'], sleep_time)


async def init():
    global task_count
    temp = task_list[:5]
    for each in temp:
        task_list.remove(each)  # 删除任务单元
        asyncio.create_task(request(each))
        task_count += 1


async def main():
    global task_count
    await init()  # 创建初始化任务 执行并发
    while True:
        print("系统当前正在执行任务数量:{}".format(task_count))
        if task_count < 5:
            if task_list:
                each = task_list[0]
                del task_list[0]
                print("添加新的任务单元:{}".format(each))
                asyncio.create_task(request(each))
                task_count += 1
            else:
                if not task_count:
                    print("所有任务单元执行完成...终止程序")
                    break
                else:
                    #  休眠等待所有任务执行完成
                    await asyncio.sleep(0.5)
        else:
            await asyncio.sleep(0.5)


if __name__ == '__main__':
    start_time = time.time()
    asyncio.run(main())
    print("总共消耗时间:{}".format(time.time() - start_time))

以上代码主要通过sleep来模拟在耗时较长的场景中怎么通过asyncio来实现异步发起任务请求以及并发执行。逻辑说明:

1、首先再次申明python的版本为3.8,因为不同的版本在python中是存在写法不同的,但就目前的版本来看,3.8版本写异步因该是最简单的了。

2、程序执行, 首先通过init()方法创建5个(系统最大并发支持任务数)协程任务。注意,在此只是创建了5个协程任务单元而已,但是还并没有执行。

3、进入while True无限循环,判断当前系统已经存在的任务数量,若大于等于5则进入else逻辑,执行await asyncio.sleep(5),当执行到此时,程序将会通过await让出cpu当前的控制权,触发程序去执行init()函数创建的5个协程任务单元的启动执行。

4、每当上述触发执行的任务单元执行完成时,系统任务数量将会减1,如此将进入到当前系统执行任务数小于最大并发数的逻辑,即创建新的协程任务单元。

5、当循环把所有任务都成功创建完成之后,系统将循环判断task_count即当前任务数是否为0(全部执行完成),如果全部执行完成则break终止,否则sleep(0.5)等待未完成的任务执行完成。

上述就是通过python来进行异步任务执行的基本逻辑了,大家颗针对自己的任务场景进行相应的调整切换即可。

转载请注明出处