当前位置: 首页 > news >正文

Python 实现大文件的高并发下载

项目背景

基于一个 scrapy-redis 搭建的分布式系统,所有item都通过重写 pipeline 存储到 redislist 中。这里我通过代码演示如何基于线程池 + 协程实现对 item 的中文件下载。

  • Item 结构

    目的是为了下载 item 中 attachments 保存的附件内容。

    {
        "crawl_time":
        "20221017 12:00:00",
        "version":
        "20221017 12:00:00",
        "data": [{
            "title": "",
            "attachments": [
                {
                    "ori_url": "https://www.baidu.com",	# 文件地址
                    "path": "",	# 文件本地保存路径
                    "filename": "xxx"	# 文件名称
                }
            ]
        }]
    }
    

一、批量获取 item

为了能够提高数据的存储效率,选择从 redis 中弹出多个 item,但当前部署的 redis 版本为 5.0lpop 不支持同时弹出多个数据,需要通过 LRANGELTRIM 命令实现,但是两个命令执行不是原子操作,在多线程的情况下会导致数据异常,因此通过 lua 脚本执行批量弹出多个 item

1.1 lua 脚本

在这里插入图片描述

1.2 读取数据

设定好批量读取的大小,执行 lua 脚本,获取数据。
在这里插入图片描述

二、并发

2.1 线程池

使用线程池去管理这么多 item 下载任务的原因:

  • 减少频繁创建和销毁线程的开销
  • 控制并发数量,防止不断创建线程导致资源耗尽
  • 复用线程,减少线程切换开销

将获取到的 data 进行分片,分片后的数据交给多个线程去下载,提高并发效率。
在这里插入图片描述

2.2 协程任务

每个线程新建一个事件循环对象 loop,用来管理分片后的 data 协程任务。

为了复用 TCP 连接和 session,选择让分片 data 共享一个 TCPConnectorClientSession 对象。这是基于 data 分片大小大概率是同一个网站的数据设计的,可以降低连接创建会话管理的的资源消耗。
在这里插入图片描述

2.3 协程并发

通过 asyncio.gather 实现协程并发。
在这里插入图片描述

三、大文件分块

下载文件时,如果文件比较大,网络又不稳定的情况下,很容易导致下载失败,因此这里通过将文件分块下载优化流程。

3.1 分块

对文件分块之前,先要获取文件大小。向服务器发送一个预请求 head,来获取文件长度,这样可以避免获取整个文件,减少网络传输耗时。
在这里插入图片描述
然后对文件进行分块处理,在传输中,需要平衡 网络拥塞请求频次 导致的消耗,这里选择将文件分为 1024 * 1024 也就是 1 MB 的块大小。

使用 asyncio.Semaphore 控制 同时进行的下载任务数量,避免过多并发导致服务器崩溃。
在这里插入图片描述

3.2 下载

修改 headers 中的 Range 获取文件指定块大小的内容。

通过装饰器实现文件的断点续传功能,防止因网络不稳定导致文件内容缺失。
在这里插入图片描述
当文件的某个块下载失败,超出重试次数时,取消所有该文件块的下载任务,暂时放弃该文件,记录到失败下载队列中保存,避免因为问件本就损坏这种情况导致不断重试。
在这里插入图片描述
异步装饰器的实现
在这里插入图片描述

3.3 拼接

result 按顺序返回请求的结果,将请求的文件块拼接完成。
在这里插入图片描述

相关文章:

  • 躲藏博弈中的策略优化:整合历史数据、概率论与博弈论
  • docker pull 镜像问题
  • RGV调度(四)--排队算法
  • 智能电话机器人的技术原理是什么?AI语音机器人评判标准是什么?
  • 数学建模之数学模型-3:动态规划
  • Liunx启动kafka并解决kafka时不时挂掉的问题
  • 用Python实现持续集成与部署(CI/CD)流程:自动化测试、构建与部署
  • 《AI浪潮中的璀璨新星:Meta Llama、Ollama与DeepSeek的深度剖析》:此文为AI自动生成
  • 基于yolov8+streamlit实现目标检测系统带漂亮登录界面
  • 第三周日志-web(2)
  • 使用AOP + Prometheus + node-exporter + grafana 实现Java系统的接口监控(实操)
  • 蓝桥杯好题推荐---子集
  • 05 | 使用 Cobra 包来构建你的 Go 项目
  • 11a-PPDU
  • 未来社交媒体的发展趋势:TikTok 与虚拟现实的结合
  • 编程自学指南:java程序设计开发,多线程编程,为什么需要多线程?线程的创建与启动,线程同步与锁机制,线程池
  • HarmonyOS NEXT - 电商App实例三( 网络请求axios)
  • blender使用初体验(甜甜圈教程)
  • 软件/硬件I2C读写MPU6050
  • 嵌入式八股ARM篇
  • 普京确定俄乌谈判俄方代表团名单
  • 外交部:各方应为俄乌双方恢复直接对话创造条件
  • 多个侵华日军细菌战部队留守名簿文件首次公布
  • 真人秀《幸存者》百万美元奖金,25年间“缩水”近一半
  • 上海能源科技发展有限公司原董事长李海瑜一审获刑13年
  • 马上评丨75万采购300元设备,仅仅终止采购还不够