Python批量下载并显示统计进度

效果:

实现脚本:

downapk_thread_100.py
import requests
import threading
import time
import sys
from queue import Queue
from dataclasses import dataclass
from typing import Dict, List
import json


@dataclass
class ThreadStatus:
    thread_id: int
    current_task: int = 0
    status: str = "空闲"
    progress: float = 0
    speed: float = 0
    downloaded: int = 0
    start_time: float = 0


class SimpleMultiDownloader:
    def __init__(self, url, total_tasks=100, max_threads=10):
        self.url = url
        self.total_tasks = total_tasks
        self.max_threads = max_threads
        self.task_queue = Queue()

        # 初始化线程状态
        self.threads_status: Dict[int, ThreadStatus] = {}
        for i in range(1, max_threads + 1):
            self.threads_status[i] = ThreadStatus(thread_id=i)

        # 全局统计
        self.global_stats = {
            'completed': 0,
            'failed': 0,
            'total_size': 0,
            'start_time': time.time(),
            'speeds': []
        }
        self.lock = threading.Lock()
        self.display_active = True

    def clear_screen(self):
        """清屏"""
        os.system('cls' if os.name == 'nt' else 'clear')

    def display_status(self):
        """显示状态表格"""
        while self.display_active:
            self.clear_screen()

            print("┌" + "─" * 78 + "┐")
            print("│" + "多线程下载监控".center(78) + "│")
            print("├" + "─" * 78 + "┤")

            # 全局统计
            with self.lock:
                completed = self.global_stats['completed']
                failed = self.global_stats['failed']
                total_done = completed + failed
                elapsed = time.time() - self.global_stats['start_time']

                if completed > 0:
                    avg_speed = sum(self.global_stats['speeds']) / len(self.global_stats['speeds'])
                else:
                    avg_speed = 0

            progress = total_done / self.total_tasks * 100
            bar_length = 40
            filled = int(bar_length * progress / 100)
            progress_bar = "█" * filled + "░" * (bar_length - filled)

            print(f"│ 总进度: [{progress_bar}] {progress:6.1f}%")
            print(f"│ 成功: {completed:4d}  失败: {failed:4d}  总计: {total_done:4d}/{self.total_tasks:4d}")
            print(f"│ 用时: {elapsed:7.1f}s   平均速度: {avg_speed:7.1f} KB/s")
            print("├" + "─" * 78 + "┤")
            print("│ 线程ID │   任务   │       状态       │   进度   │   速度   │   下载量   │")
            print("├" + "─" * 78 + "┤")

            # 显示每个线程状态
            with self.lock:
                for thread_id in sorted(self.threads_status.keys()):
                    status = self.threads_status[thread_id]

                    # 状态颜色/图标
                    if status.status == "完成":
                        status_icon = "✅"
                    elif "失败" in status.status:
                        status_icon = "❌"
                    elif status.status == "下载中":
                        status_icon = "⏬"
                    else:
                        status_icon = "⏳"

                    # 格式化显示
                    task_str = f"{status.current_task:4d}" if status.current_task > 0 else "等待"
                    status_str = f"{status_icon} {status.status[:12]:12s}"
                    progress_str = f"{status.progress:6.1f}%" if status.progress > 0 else "等待"
                    speed_str = f"{status.speed:7.1f}" if status.speed > 0 else "等待"
                    size_str = f"{status.downloaded / 1024:7.1f}KB" if status.downloaded > 0 else "等待"

                    print(
                        f"│ {thread_id:6d} │ {task_str:8s} │ {status_str:16s} │ {progress_str:8s} │ {speed_str:8s} │ {size_str:10s} │")

            print("└" + "─" * 78 + "┘")
            print("按 Ctrl+C 退出监控 (下载继续)")

            # 检查是否完成
            if total_done >= self.total_tasks:
                print("\n✅ 所有任务完成!")
                self.display_active = False
                break

            time.sleep(0.3)

    def download_worker(self, thread_id):
        """工作线程"""
        while True:
            try:
                task_id = self.task_queue.get(timeout=1)

                # 更新线程状态
                with self.lock:
                    self.threads_status[thread_id].current_task = task_id
                    self.threads_status[thread_id].status = "准备中"
                    self.threads_status[thread_id].start_time = time.time()

                # 执行下载
                success = self.perform_download(thread_id, task_id)

                # 更新全局统计
                with self.lock:
                    if success:
                        self.global_stats['completed'] += 1
                    else:
                        self.global_stats['failed'] += 1

                self.task_queue.task_done()

            except:
                break

    def perform_download(self, thread_id, task_id):
        """执行下载任务"""
        try:
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'Accept': '*/*',
                'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                'Referer': 'https://fly.walkera.cn/'
            }

            with self.lock:
                self.threads_status[thread_id].status = "连接中"

            # 获取文件大小
            response = requests.get(self.url, headers=headers, stream=True, timeout=30)
            response.raise_for_status()

            # 获取文件大小
            file_size = int(response.headers.get('content-length', 0))

            downloaded = 0
            start_time = time.time()
            last_update = start_time

            with self.lock:
                self.threads_status[thread_id].status = "下载中"

            # 流式下载
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    downloaded += len(chunk)

                    # 更新显示(限制更新频率)
                    current_time = time.time()
                    if current_time - last_update > 0.1:  # 每0.1秒更新一次
                        elapsed = current_time - start_time
                        speed = downloaded / elapsed / 1024 if elapsed > 0 else 0
                        progress = (downloaded / file_size * 100) if file_size > 0 else 0

                        with self.lock:
                            self.threads_status[thread_id].progress = progress
                            self.threads_status[thread_id].speed = speed
                            self.threads_status[thread_id].downloaded = downloaded

                        last_update = current_time

            # 下载完成
            end_time = time.time()
            download_time = end_time - start_time
            speed = downloaded / download_time / 1024 if download_time > 0 else 0

            with self.lock:
                self.threads_status[thread_id].status = "完成"
                self.threads_status[thread_id].progress = 100
                self.threads_status[thread_id].speed = speed
                self.global_stats['total_size'] += downloaded
                self.global_stats['speeds'].append(speed)

            return True

        except Exception as e:
            with self.lock:
                self.threads_status[thread_id].status = f"失败: {str(e)[:15]}"
                self.threads_status[thread_id].progress = -1

            return False

    def run(self):
        """运行下载器"""
        print("开始多线程下载...")
        print(f"URL: {self.url}")
        print(f"任务数: {self.total_tasks}")
        print(f"线程数: {self.max_threads}")

        # 添加任务到队列
        for i in range(self.total_tasks):
            self.task_queue.put(i + 1)

        # 启动显示线程
        display_thread = threading.Thread(target=self.display_status, daemon=True)
        display_thread.start()

        # 启动工作线程
        threads = []
        for i in range(self.max_threads):
            thread = threading.Thread(target=self.download_worker, args=(i + 1,))
            thread.daemon = True
            thread.start()
            threads.append(thread)

        try:
            # 等待所有任务完成
            self.task_queue.join()

            # 等待显示线程结束
            display_thread.join(timeout=2)

        except KeyboardInterrupt:
            print("\n用户中断")
        finally:
            self.display_active = False

        # 显示最终统计
        self.show_summary()

    def show_summary(self):
        """显示最终统计"""
        total_time = time.time() - self.global_stats['start_time']

        print("\n" + "=" * 60)
        print("下载完成! 最终统计:")
        print("=" * 60)

        with self.lock:
            completed = self.global_stats['completed']
            failed = self.global_stats['failed']

            print(f"总任务数: {self.total_tasks}")
            print(f"成功: {completed} ({completed / self.total_tasks * 100:.1f}%)")
            print(f"失败: {failed} ({failed / self.total_tasks * 100:.1f}%)")
            print(f"总用时: {total_time:.2f} 秒")
            print(f"总下载量: {self.global_stats['total_size'] / 1024 / 1024:.2f} MB")

            if completed > 0:
                avg_speed = sum(self.global_stats['speeds']) / len(self.global_stats['speeds'])
                print(f"平均速度: {avg_speed:.1f} KB/s")
                print(f"吞吐量: {self.global_stats['total_size'] / total_time / 1024:.1f} KB/s")


# 使用示例
if __name__ == "__main__":
    import os

    url = "https://fly.walkera.cn/fd/download?name=WKFLY-1.3.72-1018-release.apk"

    downloader = SimpleMultiDownloader(
        url=url,
        total_tasks=50,  # 减少任务数便于观察
        max_threads=8  # 线程数
    )

    downloader.run()

【直流微电网】径向直流微电网的状态空间建模与线性化:一种耦合DC-DC变换器状态空间平均模型的方法 (Matlab代码实现)内容概要:本文介绍了径向直流微电网的状态空间建模与线性化方法,重点提出了一种基于耦合DC-DC变换器状态空间平均模型的建模策略。该方法通过对系统中多个相互耦合的DC-DC变换器进行统一建模,构建出整个微电网的集中状态空间模型,在此基础上实施线性化处理,便于后续的小信号分析与稳定性研究。文中详细阐述了建模过程中的关键步骤,包括电路拓扑分析、状态变量选取、平均化处理以及雅可比矩阵的推导,最终通过Matlab代码实现模型仿真验证,展示了该方法在动态响应分析和控制器设计中的有效性。; 适合人群:具备电力电子、自动控制理论基础,熟悉Matlab/Simulink仿真工具,从事微电网、新能源系统建模与控制研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握直流微电网中多变换器系统的统一建模方法;②理解状态空间平均法在非线性电力电子系统中的应用;③实现系统线性化用于稳定性分析与控制器设计;④通过Matlab代码复现和扩展模型,服务于科研仿真与教学实践。; 阅读建议:建议读者结合Matlab代码逐步理解建模流程,重点关注状态变量的选择与平均化处理的数学推导,同时可尝试修改系统参数或拓扑结构以加深对模型通用性和适应性的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宏权实验室

有你的鼓励,我会更加努力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值