添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
礼貌的炒饭  ·  Docker ...·  1 年前    · 

为什么要多线程?单个线程不能下载吗?多线程能占满网络实现宽带的满速下载而单线程不能。

举个栗子:你的宽带是 100Mb/s ,理论上最大下载速度是 100/8=12.5MB/s 。你要下载一个 843MB 的视频,采用单线程下载你需要 560 秒才能下载完,而采用多线程(12个线程)你却可以在 93 秒内完成下载,时间将近缩短了 6 倍。

如果计算一下网络的利用率,你还可以发现:单线程的平均下载速度是 1.50MB/s ,而多线程的平均下载速度是 9.06MB/s ,多线程几乎将网络资源利用满了。这就是多线程的好处!

requests 库用于从服务器请求资源。

pip3 install requests

一个843MBMP4格式的视频文件。

https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo/1250921_c7af3a2b73d03604f6421ef11134af72.mp4

使用concurrent.futures模块的子类ThreadPoolExecutor创建线程池实现多线程。

from concurrent.futures import ThreadPoolExecutor
from requests import get, head
import time
class downloader:
    def __init__(self, url, num, name):
        self.url = url
        self.num = num
        self.name = name
        self.getsize = 0
        r = head(self.url, allow_redirects=True)
        self.size = int(r.headers['Content-Length'])
    def down(self, start, end, chunk_size=10240):
        headers = {'range': f'bytes={start}-{end}'}
        r = get(self.url, headers=headers, stream=True)
        with open(self.name, "rb+") as f:
            f.seek(start)
            for chunk in r.iter_content(chunk_size):
                f.write(chunk)
                self.getsize += chunk_size
    def main(self):
        start_time = time.time()
        f = open(self.name, 'wb')
        f.truncate(self.size)
        f.close()
        tp = ThreadPoolExecutor(max_workers=self.num)
        futures = []
        start = 0
        for i in range(self.num):
            end = int((i+1)/self.num*self.size)
            future = tp.submit(self.down, start, end)
            futures.append(future)
            start = end+1
        while True:
            process = self.getsize/self.size*100
            last = self.getsize
            time.sleep(1)
            curr = self.getsize
            down = (curr-last)/1024
            if down > 1024:
                speed = f'{down/1024:6.2f}MB/s'
            else:
                speed = f'{down:6.2f}KB/s'
            print(f'process: {process:6.2f}% | speed: {speed}', end='\r')
            if process >= 100:
                print(f'process: {100.00:6}% | speed:  00.00KB/s', end=' | ')
                break
        tp.shutdown()
        end_time = time.time()
        total_time = end_time-start_time
        average_speed = self.size/total_time/1024/1024
        print(f'total-time: {total_time:.0f}s | average-speed: {average_speed:.2f}MB/s')
if __name__ == '__main__':
    url = 'https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo/1250921_c7af3a2b73d03604f6421ef11134af72.mp4'
    down = downloader(url, 12, 'test.mp4')
    down.main()
import requests
import time
start = time.time()
url = 'https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo/1250921_c7af3a2b73d03604f6421ef11134af72.mp4'
res = requests.get(url, stream=True)
with open('test.mp4', 'wb') as f:
    for chunk in res.iter_content(chunk_size=10240):
        f.write(chunk)
end = time.time()
print(end-start)

同样下载一个843MB的视频,多线程和单线程的对比分析结果如下:

对比项多线程单线程
总计用时93s560s
平均速度9.06MB/s1.50MB/s

这里还和多线程网络下载器IDM对比了一下,发现用python实现的多线程下载器的下载速度并不亚于IDM,如果继续开发,实现断点续传和GUI后,应该可以完全替代IDM的下载功能。

  • 多线程
  • 断点续传
  • GUI
[0] https://blog.csdn.net/qq_41488943/article/details/107118377
[1] https://docs.python.org/zh-cn/3.8/library/concurrent.futures.html#threadpoolexecutor
[2] https://requests.readthedocs.io/zh_CN/latest/user/quickstart.html#id9
深夜忽然想下载一点电子书来扩充一下kindle,就想起来python学得太浅,什么“装饰”啊、“多线程”啊都没有学到。
想到廖雪峰大神的python教程很经典、很著名。就想找找有木有pdf版的下载,结果居然没找到!!CSDN有个不完整的还骗走了我一个积分!!尼玛!!
怒了,准备写个程序直接去爬廖雪峰的教程,然后再html转成电子书。
过程很有趣呢,用浅薄的python知识,写python程序,去爬python教程,来学习python。想想有点小激动……
果然python很是方便,50行左右就OK了。直接贴代码:
# coding:utf-8
import urllib
                                    本文是来自读者Sheep投稿https://zhuanlan.zhihu.com/p/369531344前言下载文件是我们生活中的一个常见的需求,因此衍生的下载工具也非常多,各有各的优势以...
                                    【爬虫】案例03:某图网图片多线程下载
本文介绍了进程与线程的基本概念和关系;使用threading.Thread实多线程爬虫,在提高爬虫效率的同时,也引发了一些思考。
                                    在 Python 中使用多线程爬虫下载文件,可以使用 threading 模块中的 Thread 类。
首先,需要创建一个函数来下载文件。然后,创建一个 Thread 对象,并将下载文件的函数作为参数传递给它。最后,调用 Thread 对象的 start() 方法来开始新线程。
下面是一个示例代码,假设已有一个函数 download_file(url) 用于下载文件:
import threadi...
                                    本文非常浅层的演示了python如何实现多线程文件下载,核心取决于现代服务基本都支持范围下载的前提下。关于断点续传,文章已提供基本理论和实现思路,有兴趣通过python实现下载的朋友都可以专门去实现一下。......
多进程和多线程都可以执行多个任务,线程是进程的一部分。线程的特点是线程之间可以共享
内存和变量,资源消耗少(不过在Unix环境中,多进程和多线程资源调度消耗差距不明显,
Unix调度较快),缺点是线程之间的同步和加锁比较麻烦。
2、Python多线程创建
在Python中,同样可以实现多线程,有两个标准模块thread和threading,不过我们主要使用
更高级的threading模块。