python多线程http下载实现示例


Posted in Python onDecember 30, 2013

测试平台 Ubuntu 13.04 X86_64 Python 2.7.4

花了将近两个小时, 问题主要刚开始没有想到传一个文件对象到线程里面去, 导致下载下来的文件和源文件MD5不一样,浪费不少时间.

有兴趣的同学可以拿去加上参数,改进下, 也可以加上断点续传.

# -*- coding: utf-8 -*-
# Author: ToughGuy
# Email: wj0630@gmail.com
# 写这玩意儿是为了初步了解下python的多线程机制
# 平时没写注释的习惯, 这次花时间在代码里面写上注释也是希望有问题的地方请各位指正, 因为可能我自己也没弄明白.
# 测试平台 Ubuntu 13.04 X86_64 Python 2.7.4
import threading
import urllib2
import sys
max_thread = 10
# 初始化锁
lock = threading.RLock()
class Downloader(threading.Thread):
    def __init__(self, url, start_size, end_size, fobj, buffer):
        self.url = url
        self.buffer = buffer
        self.start_size = start_size
        self.end_size = end_size
        self.fobj = fobj
        threading.Thread.__init__(self)
    def run(self):
        """
            马甲而已
        """
        with lock:
            print 'starting: %s' % self.getName()
        self._download()
    def _download(self):
        """
            我才是搬砖的
        """
        req = urllib2.Request(self.url)
        # 添加HTTP Header(RANGE)设置下载数据的范围
        req.headers['Range'] = 'bytes=%s-%s' % (self.start_size, self.end_size)
        f = urllib2.urlopen(req)
        # 初始化当前线程文件对象偏移量
        offset = self.start_size
        while 1:
            block = f.read(self.buffer)
            # 当前线程数据获取完毕后则退出
            if not block:
                with lock:
                    print '%s done.' % self.getName()
                break
            # 写如数据的时候当然要锁住线程
            # 使用 with lock 替代传统的 lock.acquire().....lock.release()
            # 需要python >= 2.5
            with lock:
                sys.stdout.write('%s saveing block...' % self.getName())
                # 设置文件对象偏移地址
                self.fobj.seek(offset)
                # 写入获取到的数据
                self.fobj.write(block)
                offset = offset + len(block)
                sys.stdout.write('done.\n')

def main(url, thread=3, save_file='', buffer=1024):
    # 最大线程数量不能超过max_thread
    thread = thread if thread <= max_thread else max_thread
    # 获取文件的大小
    req = urllib2.urlopen(url)
    size = int(req.info().getheaders('Content-Length')[0])
    # 初始化文件对象
    fobj = open(save_file, 'wb')
    # 根据线程数量计算 每个线程负责的http Range 大小
    avg_size, pad_size = divmod(size, thread)
    plist = []
    for i in xrange(thread):
        start_size = i*avg_size
        end_size = start_size + avg_size - 1
        if i == thread - 1:
            # 最后一个线程加上pad_size
            end_size = end_size + pad_size + 1
        t = Downloader(url, start_size, end_size, fobj, buffer)
        plist.append(t)
    #  开始搬砖
    for t in plist:
        t.start()
    # 等待所有线程结束
    for t in plist:
        t.join()
    # 结束当然记得关闭文件对象
    fobj.close()
    print 'Download completed!'
if __name__ == '__main__':
    url = 'http://192.168.1.2:8082/downloads/10M.zip'
    main(url=url, thread=10, save_file='test.iso', buffer=4096)
Python 相关文章推荐
深入理解Python 代码优化详解
Oct 27 Python
将TensorFlow的模型网络导出为单个文件的方法
Apr 23 Python
python pandas库中DataFrame对行和列的操作实例讲解
Jun 09 Python
python基础学习之如何对元组各个元素进行命名详解
Jul 12 Python
windows下cx_Freeze生成Python可执行程序的详细步骤
Oct 09 Python
Python一行代码实现快速排序的方法
Apr 30 Python
Python面向对象进阶学习
May 21 Python
Django项目主urls导入应用中views的红线问题解决
Aug 10 Python
python中对_init_的理解及实例解析
Oct 11 Python
解决torch.autograd.backward中的参数问题
Jan 07 Python
Python多线程获取返回值代码实例
Feb 17 Python
Python TestSuite生成测试报告过程解析
Jul 23 Python
python正则匹配查询港澳通行证办理进度示例分享
Dec 27 #Python
python模拟登录百度代码分享(获取百度贴吧等级)
Dec 27 #Python
python读文件逐行处理的示例代码分享
Dec 27 #Python
python调用cmd复制文件代码分享
Dec 27 #Python
win7安装python生成随机数代码分享
Dec 27 #Python
python正则匹配抓取豆瓣电影链接和评论代码分享
Dec 27 #Python
python正则表达式去掉数字中的逗号(python正则匹配逗号)
Dec 25 #Python
You might like
了解咖啡雨林联盟认证 什么是雨林认证 雨林认证是什么意思
2021/03/05 新手入门
Dedecms常用函数解析
2008/02/01 PHP
PHP数字字符串左侧补0、字符串填充和自动补齐的几种方法
2014/05/10 PHP
PHP开启opcache提升代码性能
2015/04/26 PHP
ThinkPHP中Common/common.php文件常用函数功能分析
2016/05/20 PHP
jQuery 前的按键判断代码
2010/03/19 Javascript
jquery的Theme和Theme Switcher使用小结
2010/09/08 Javascript
jQuery 1.8 Release版本发布了
2012/08/14 Javascript
使用forever管理nodejs应用教程
2014/06/03 NodeJs
javascript继承的六大模式小结
2015/04/13 Javascript
JavaScript获取URL汇总
2015/06/08 Javascript
基于Layer+jQuery的自定义弹框
2020/05/26 Javascript
angular 基于ng-messages的表单验证实例
2017/05/04 Javascript
vue二级路由设置方法
2018/02/09 Javascript
Vue.set()动态的新增与修改数据,触发视图更新的方法
2018/09/15 Javascript
BootStrap模态框闪退问题实例代码详解
2018/12/10 Javascript
关于vue.js中实现方法内某些代码延时执行
2019/11/14 Javascript
vue实现学生信息管理系统
2020/05/30 Javascript
swiper4实现移动端导航栏tab滑动切换
2020/10/16 Javascript
[00:33]2016完美“圣”典风云人物:Sccc宣传片
2016/12/03 DOTA
Python3 pip3 list 出现 DEPRECATION 警告的解决方法
2019/02/16 Python
Python 中Django安装和使用教程详解
2019/07/03 Python
python将字符串转换成json的方法小结
2019/07/09 Python
在Django的View中使用asyncio的方法
2019/07/12 Python
Python使用selenium + headless chrome获取网页内容的方法示例
2019/10/16 Python
解决pycharm每次打开项目都需要配置解释器和安装库问题
2020/02/26 Python
Django models文件模型变更错误解决
2020/05/11 Python
Pycharm导入anaconda环境的教程图解
2020/07/31 Python
HomeAway英国:全球领先的度假租赁在线市场
2020/02/03 全球购物
园林资料员岗位职责
2013/12/30 职场文书
人力资源经理的岗位职责
2014/03/02 职场文书
学习演讲稿范文
2014/05/10 职场文书
介绍信格式
2015/01/30 职场文书
2016秋季小学开学寄语
2015/12/03 职场文书
MySQL数据库事务的四大特性
2022/04/20 MySQL
Windows Server 2016 配置 IIS 的详细步骤
2022/04/28 Servers