请教关于 Python 多线程下载器问题

Chan775:刚学完 python 不久,想做个小爬虫练练手,于是整了个小爬虫在 vps 持续爬取某个小视频网站的发布的小视频,小视频的大小为 1-200M,小爬虫负责下载视频的部分很简单,直接 r = requests.get(url),然后把 r.content 写入文件。

后来觉得下载效率好像不行,于是上网搜了一下多线程下载器,便开始重写下载视频部分的代码了,成品如下,在我的电脑上能正常运行,但在 vps 上持续运行的话,有不少问题,不仅内存占用大(占用 200 多 M 的内存),而且时不时出现Max retries exceeded with url的错误。

from threading import Thread

import requests


class Download:
    def __init__(self, url):
        self.url = url
        self.ua = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0'}
        r = requests.head(self.url, headers=self.ua)
        # 循环寻址
        while r.status_code == 301 or r.status_code == 302:
            self.url = r.headers['Location']
            r = requests.head(self.url, headers=self.ua)
        self.name = self.url.split('?')[0].split('/')[-1]
        self.size = int(r.headers['Content-Length'])
        # 创建等大空文件
        f = open(self.name, "wb")
        f.truncate(self.size)
        f.close()
        # 根据文件大小分配线程
        if self.size < 5 * 1024 * 1024:
            self.thread_num = 1
        elif self.size < 10 * 1024 * 1024:
            self.thread_num = 2
        elif self.size < 20 * 1024 * 1024:
            self.thread_num = 4
        elif self.size < 40 * 1024 * 1024:
            self.thread_num = 8
        else:
            self.thread_num = 16
        # 确定文件块大小
        self.part = self.size // self.thread_num

    def dl(self, start, end):
        header = {'Range': 'bytes={}-{}'.format(start, end)}
        header.update(self.ua)
        with requests.get(self.url, headers=header, stream=True) as r:
            with open(self.name, 'rb+') as f:
                f.seek(start)
                f.write(r.content)

    @staticmethod
    def unit_conversion(byte):
        byte = int(byte)
        if byte > 1024:
            res = byte / 1024
            if res < 1024:
                res = float('%.2f' % res)
                return str(res) + 'KB'
            elif res < 1024 * 1024:
                res = res / 1024
                res = float('%.2f' % res)
                return str(res) + 'MB'
            else:
                res = res / (1024 * 1024)
                res = float('%.2f' % res)
                return str(res) + 'GB'
        else:
            return str(byte) + 'B'

    def run(self):
        thread_list = []
        for i in range(self.thread_num - 1):
            start = i * self.part
            end = (i + 1) * self.part
            t = Thread(target=self.dl, args=(start, end))
            thread_list.append(t)
        # 最后一部分
        start = (self.thread_num - 1) * self.part
        end = self.size
        t = Thread(target=self.dl, args=(start, end))
        thread_list.append(t)
        # 启动所有子线程
        for t in thread_list:
            t.start()
        # 子进程合并到主线程
        for t in thread_list:
            t.join()
        print(f'{Download.unit_conversion(self.size)} {self.name}下载完成!')
        return self.name, self.size


if __name__ == '__main__':
    t = Download('http://www.baidu.com').run()
    print(t)

请教大家几个问题:
1 、多线程下载的时候,多个线程读取同一个文件,不同的线程在文件的不同位置写入内容,需要加入线程锁吗?我感觉它们写入的部分不同,好像没有冲突啊

2 、我在网上查到Max retries exceeded with url的错误是由于 http 连接过多引起的,网上给出的方法有用 with 语句打开 requests.get(url)来确保连接会被关闭,还有的是建议直接加 response.close()关闭,还有的用with closing(requests.get(img_url, stream=True)) as r:,哪种方法比较靠谱呢?

3 、俺还有啥可以优化改进的地方?

ysc3839:直接调用 aria2 去下载

virtuemartx:多线程不加锁也行 是不是因为 python gil ? 导致多线程也跟 nodejs 异步差不多?

Python 如何查某关键词在百度网页第几页?

cizimo:例如,在百度搜索 XXX 关键词后,想知道包含 YYY 的词在搜索结果的第几页? 这个能做到吗? 或者说有没有教程,砸一个链接给我呗,谢谢大家啦

Python 有没有监听鼠标点击网页相关元素的包呢?

18870715400:具体需求 比如说打开了 www.baidu.com ,当你鼠标点击了“百度一下”就可以获得这个对应的 id 或者是对应的 xpath 语法 如果没有对应的包,那么有什么可以具体实现的思路呢?

Python 现在最好用的包管理是啥?

maichael:最近为了给测试搭自动化测试,重新开始搞起 Python,但是整体工程结构比较苦恼。 重点是版本管理,requirements.txt 感觉不怎么好用。Pipenv? Tox? 还是其它的啥? 以及像 package.json 里 scripts 的用法,python 有类似的吗?cdyrhh:poetry

Python 如何优雅地处理子线程异常?

Te11UA:目前比较多的做法还是如下,出于担心未知异常、没有记录日志就退出子线程的情况下,在函数用一个大的 try-except 来进行 handle,或者是将主要逻辑放到 test_sth 中,使用 try-except 来捕获: def run(): try: test_sth() ... except Exception: log_exception…

Python GPU资源利用 - python

我有一个Python脚本在某些深度学习模型上运行推理。有什么办法可以找出GPU资源的利用率水平?例如,使用着色器,float16乘法器等。我似乎在网上找不到太多有关这些GPU资源的文档。谢谢! 参考方案 您可以尝试在像Renderdoc这样的GPU分析器中运行pyxthon应用程序。它将分析您的跑步情况。您将能够获得有关已使用资源,已用缓冲区,不同渲染状态上…