美文网首页
寻找最快的图片下载方式

寻找最快的图片下载方式

作者: 任然_c117 | 来源:发表于2019-05-01 21:15 被阅读0次

    首先因为工作原因,批量下载很常见,之前一直也没太关注这一块,但是闲下来对这个块的确有点感兴趣,
    于是在实验中试着进行一些操作,本文主要探讨,异步,单线程,多线程,以及多进程的情况下,图片
    下载速度的问题。

    代码部分使用的python,如果有什么不对的地方欢迎指出,一同进步。

    首先准备了100个图片链接的列表,这里因为数据源的问题就不透露了。

    单线程示例:

    最普通的方式,没什么好说的。

    def main():
        targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
        if not os.path.isdir(targetDir):  # 不存在创建路径
            os.makedirs(targetDir)
        num = 0
        for i in _list:
            downloadImage(i, targetDir, num)
            num = num + 1
    
    def downloadImage(img_url,fileDir,fileName):
        r = requests.get(img_url, headers)
        t = os.path.join(fileDir, str(fileName) + '.jpg')  # 指定目录
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r.content)  # 保存图片到本地指定目录
    
    if __name__ == '__main__':
        start = time.clock()
        main()
        end = time.clock()
        print("程序运行时间:" + str(end - start))
    

    多线程(第一版)

    最普通的多线程,一个请求一个线程。

    def main():
        targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
        if not os.path.isdir(targetDir):  # 不存在创建路径
            os.makedirs(targetDir)
        num = 0
        for i in _list:
            t =threading.Thread(target=downloadImage, args=(i, targetDir, num))
            t.start()
            t.join()
            num = num + 1
    
    def downloadImage(img_url,fileDir,fileName):
        r = requests.get(img_url, headers)
        t = os.path.join(fileDir, str(fileName) + '.jpg')  # 指定目录
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r.content)  # 保存图片到本地指定目录
    
    if __name__ == '__main__':
        start = time.clock()
        main()
        end = time.clock()
        print("程序运行时间:" + str(end - start))
    

    多线程(第二版)

    使用了线程池的方式.好像明白了为什么很少人这么玩。

    def main():
        targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
        if not os.path.isdir(targetDir):  # 不存在创建路径
            os.makedirs(targetDir)
        num = 0
        pool = threadpool.ThreadPool(10)
        for i in _list:
            dict_vars_1 = {'img_url': i, 'fileDir': targetDir, 'fileName': num}
            func_var = [(None, dict_vars_1)]
            requests = threadpool.makeRequests(downloadImage, func_var)
            [pool.putRequest(req) for req in requests]
            pool.wait()
            num = num + 1
    
    def downloadImage(img_url,fileDir,fileName):
        r = requests.get(img_url, headers)
        t = os.path.join(fileDir, str(fileName) + '.jpg')  # 指定目录
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r.content)  # 保存图片到本地指定目录
    
    if __name__ == '__main__':
        start = time.clock()
        main()
        end = time.clock()
        print("程序运行时间:" + str(end - start))
    

    多进程(第一版)

    一次下载起一个进程,起进程开销大实则体验不好。

    def main():
        targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
        if not os.path.isdir(targetDir):  # 不存在创建路径
            os.makedirs(targetDir)
        num = 0
        for i in _list:
            p = Process(target=downloadImage, args=(i,targetDir,num))
            p.start()
            p.join()
            num = num + 1
    
    def downloadImage(img_url,fileDir,fileName):
        r = requests.get(img_url, headers)
        t = os.path.join(fileDir, str(fileName) + '.jpg')  # 指定目录
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r.content)  # 保存图片到本地指定目录
    
    if __name__ == '__main__':
        start = time.clock()
        main()
        end = time.clock()
        print("程序运行时间:" + str(end - start))
    

    多进程第二版

    可以说,非常快了,只起了四个进程,减少了很多开销,速度的确得到了飞升。

    def main():
        targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
        if not os.path.isdir(targetDir):  # 不存在创建路径
            os.makedirs(targetDir)
        num = 0
        p = Pool(4)
        for i in _list:
            p.apply_async(downloadImage, args=(i,targetDir,num,))
            num = num + 1
        p.close()
        p.join()
    
    def downloadImage(img_url,fileDir,fileName):
        r = requests.get(img_url, headers)
        t = os.path.join(fileDir, str(fileName) + '.jpg')  # 指定目录
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r.content)  # 保存图片到本地指定目录
    
    if __name__ == '__main__':
        start = time.clock()
        main()
        end = time.clock()
        print("程序运行时间:" + str(end - start))
    

    异步

    基础的异步,没啥好介绍的

    def main():
        targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
        if not os.path.isdir(targetDir):  # 不存在创建路径
            os.makedirs(targetDir)
        num = 0
        loop = asyncio.get_event_loop()
        for i in _list:
            loop.run_until_complete(downloadImage(i, targetDir, num))
            num = num + 1
    
    async def downloadImage(img_url,fileDir,fileName):
        r = requests.get(img_url, headers)
        t = os.path.join(fileDir, str(fileName) + '.jpg')  # 指定目录downloadImage
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r.content)  # 保存图片到本地指定目录
    
    if __name__ == '__main__':
        start = time.clock()
        main()
        end = time.clock()
        print("程序运行时间:" + str(end - start))
    

    异步(第二版)

    有大佬指出上面的写法,不标准,于是加了一个版本。

    async def main():
        targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
        if not os.path.isdir(targetDir):  # 不存在创建路径
            os.makedirs(targetDir)
        num = 0
        for i in _list:
            await downloadImage(i, targetDir, num)
            num = num + 1
    
    async def downloadImage(img_url,fileDir,fileName):
        r = requests.get(img_url, headers)
        t = os.path.join(fileDir, str(fileName) + '.jpg')  # 指定目录downloadImage
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r.content)  # 保存图片到本地指定目录
    
    if __name__ == '__main__':
        start = time.clock()
        loop = asyncio.get_event_loop()
        tasks = [main()]
        loop.run_until_complete(asyncio.wait(tasks))
        loop.close()
        end = time.clock()
        print("程序运行时间:" + str(end - start))
    

    测验总结

    版本 数量 时间/s 点评
    单线程 1 58.6002 中规中矩的玩法,可能是大部分人程序的速度。
    多线程 100 14.4361 看的出来的优化速度,经常能看到的同事写法。
    多线程(线程池) 4 12.7496 这个玩法写的人很少,但是速度的确比开全量线程要快一丢丢(然并卵)。
    _ 10 18.5659
    _ 50 21.3403
    多进程 100 72.7953 由此可见,进程开销是真的很大,某种程度还不如单线程呢(强行优化真的会打脸)。
    多进程(进程池) 4 5.6596 这是什么神仙速度,如果你体验了你会爱上它.在控制一定的数量下,它会表现更加优异!
    _ 10 2.9305
    _ 50 7.6447
    异步 1 23.1643 老实说,异步了也还是单线程的本质,不过这个效率已经比较满意了。
    异步(第二版) 1 13.0175 这种异步的方式,会更快了一些。

    福利时间:

    image.png

    好了,今天的内容就到这里啦,如果你有更好的测验想法,欢迎在下方评论,留言。
    如果有错误的地方欢迎指正,谢谢!

    以上完毕!

    相关文章

      网友评论

          本文标题:寻找最快的图片下载方式

          本文链接:https://www.haomeiwen.com/subject/ntuwnqtx.html