使用asyncio让下载提速同时控制并发数量

554 阅读1分钟

现在有一个小功能需要实现:已经准备了一个或者多个文本文件,links.log,文件中的每一行都是一个下载命令,比如wget https://xxx.xx.xx/aa.mp3 这样子,一共有上千行。

也就是我们需要下载上千个mp3文件,逐个逐个去执行当然是可以的,但是何不趁机学习一下asyncio呢。

经过搜索发现可以使用asyncio的信号量这个功能来实现对并发数量的控制,这样就不至于一下子开了太多任务导致机器卡死,网卡打满,或者一下子开的太少导致总体耗时太久。

实战中使用的是并发数为4,这台M1 Macbook Pro头一次启动了自己的风扇,一直以为它风扇坏掉了。。。

image.png

import asyncio
import subprocess

async def run_command(command):
    process = await asyncio.create_subprocess_shell(command)
    await process.wait()
    print(f'Command "{command}" finished with exit code {process.returncode}')

async def run_commands(commands):
    # 创建一个限制并发数为4的信号量
    sem = asyncio.Semaphore(4)
    
    # 创建命令执行任务列表
    tasks = []
    for command in commands:
        # 使用信号量限制并发数
        async with sem:
            task = asyncio.ensure_future(run_command(command))
            tasks.append(task)
    
    # 等待所有命令执行完成
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    # 假设有100个下载任务
    link_files = ["links.log"]
    cmds = set()
    # 这里补充你的cmds即可
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run_commands(cmds))