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 删除列表里所有空格项的方法总结
Apr 18 Python
python3.7.0的安装步骤
Aug 27 Python
python3实现二叉树的遍历与递归算法解析(小结)
Jul 03 Python
python解释器spython使用及原理解析
Aug 24 Python
python实现ip地址查询经纬度定位详解
Aug 30 Python
python的range和linspace使用详解
Nov 27 Python
Python+opencv+pyaudio实现带声音屏幕录制
Dec 23 Python
python pip如何手动安装二进制包
Sep 30 Python
python如何控制进程或者线程的个数
Oct 16 Python
详解pycharm自动import所需的库的操作方法
Nov 30 Python
python通过cython加密代码
Dec 11 Python
Python合并pdf文件的工具
Jul 01 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
php单链表实现代码分享
2016/07/04 PHP
php 删除指定文件夹的实例讲解
2017/07/25 PHP
使用YII2框架实现微信公众号中表单提交功能
2017/09/04 PHP
JS函数实现动态添加CSS样式表文件
2012/12/15 Javascript
jQuery的Ajax的自动完成功能控件简要说明
2013/02/22 Javascript
jquery实现图片裁剪思路及实现
2013/08/16 Javascript
调用HttpHanlder的几种返回方式小结
2013/12/20 Javascript
原生js仿jq判断当前浏览器是否为ie,精确到ie6~8
2014/08/30 Javascript
jQuery实现简单隔行变色的方法
2016/02/20 Javascript
JavaScript中实现键值对应的字典与哈希表结构的示例
2016/06/12 Javascript
自带气泡提示的vue校验插件(vue-verify-pop)
2017/04/07 Javascript
Vue与Node.js通过socket.io通信的示例代码
2018/07/25 Javascript
Javascript之高级数组API的使用实例
2019/03/08 Javascript
微信小程序分享功能onShareAppMessage(options)用法分析
2019/04/24 Javascript
JS把字符串格式的时间转换成几秒前、几分钟前、几小时前、几天前等格式
2019/07/10 Javascript
vue中nextTick用法实例
2019/09/11 Javascript
JavaScript键盘事件响应顺序详解
2019/09/30 Javascript
python解析json实例方法
2013/11/19 Python
详解python发送各类邮件的主要方法
2016/12/22 Python
Python基于高斯消元法计算线性方程组示例
2018/01/17 Python
python 导入数据及作图的实现
2019/12/03 Python
使用python创建生成动态链接库dll的方法
2020/05/09 Python
python中Ansible模块的Playbook的具体使用
2020/05/28 Python
法国时尚童装网站:Melijoe
2016/08/10 全球购物
英国豪华文具和皮具配件经典老品牌:Smythson(斯迈森)
2018/04/19 全球购物
英国最大的在线时尚眼镜店:Eyewearbrands
2019/03/12 全球购物
Linux如何压缩可执行文件
2013/10/21 面试题
自考生毕业自我鉴定
2013/10/10 职场文书
广告业务员岗位职责
2014/02/06 职场文书
4S店售后客服自我评价
2014/04/09 职场文书
搞笑的获奖感言
2014/08/16 职场文书
2014年护士工作总结范文
2014/11/11 职场文书
大学生入党自传2015
2015/06/26 职场文书
七一慰问简报
2015/07/20 职场文书
人生一定要学会的三样东西:放下、忘记、珍惜
2019/08/21 职场文书
修改MySQL的数据库引擎为INNODB的方法
2021/05/26 MySQL