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中还原JavaScript的escape函数编码后字符串的方法
Aug 22 Python
Python提取网页中超链接的方法
Sep 18 Python
python和flask中返回JSON数据的方法
Mar 26 Python
python 实现在txt指定行追加文本的方法
Apr 29 Python
Django 跨域请求处理的示例代码
May 02 Python
Python读取xlsx文件的实现方法
Jul 04 Python
Django获取应用下的所有models的例子
Aug 30 Python
python元组和字典的内建函数实例详解
Oct 22 Python
浅谈PyTorch的可重复性问题(如何使实验结果可复现)
Feb 20 Python
Python如何把Spark数据写入ElasticSearch
Apr 18 Python
浅谈Python 参数与变量
Jun 20 Python
Python绘制词云图之可视化神器pyecharts的方法
Feb 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
PHP中PDO基础教程 入门级
2011/09/04 PHP
PHP代码优化之成员变量获取速度对比
2014/02/28 PHP
兼容ie6浏览器的php下载文件代码分享
2014/07/14 PHP
Codeigniter中mkdir创建目录遇到权限问题和解决方法
2014/07/25 PHP
UPUPW 更新 64 位 Apache 系列 PHP 7.0 正式版
2015/12/08 PHP
thinkPHP自动验证、自动添加及表单错误问题分析
2016/10/17 PHP
CodeIgniter框架实现的整合Smarty引擎DEMO示例
2019/03/28 PHP
jQuery 数据缓存data(name, value)详解及实现
2010/01/04 Javascript
Node.js:Windows7下搭建的Node.js服务(来玩玩服务器端的javascript吧,这可不是前端js插件)
2011/06/27 Javascript
javascript设计模式之工厂模式示例讲解
2014/03/04 Javascript
JavaScript使用HTML5的window.postMessage实现跨域通信例子
2014/04/11 Javascript
jquery实现鼠标滑过后动态图片提示效果实例
2015/08/10 Javascript
javascript事件绑定学习要点
2016/03/09 Javascript
javascript字符串对象常用api函数小结(连接,替换,分割,转换等)
2016/09/20 Javascript
javascript实现table单元格点击展开隐藏效果(实例代码)
2017/04/10 Javascript
Swiper 4.x 使用方法(移动端网站的内容触摸滑动)
2018/05/17 Javascript
Vue项目中跨域问题解决方案
2018/06/05 Javascript
react 移动端实现列表左滑删除的示例代码
2019/07/04 Javascript
JavaScript判断数据类型有几种方法及区别介绍
2020/09/02 Javascript
微信小程序实现自定义底部导航
2020/11/18 Javascript
Webpack3+React16代码分割的实现
2021/03/03 Javascript
Python实现的Google IP 可用性检测脚本
2015/04/23 Python
Python开发中爬虫使用代理proxy抓取网页的方法示例
2017/09/26 Python
pandas删除行删除列增加行增加列的实现
2019/07/06 Python
Python如何计算语句执行时间
2019/11/22 Python
PyTorch使用cpu加载模型运算方式
2020/01/13 Python
pycharm如何实现跨目录调用文件
2020/02/28 Python
英国网上花店:Bunches
2016/11/29 全球购物
澳大利亚床上用品、浴巾和家居用品购物网站:Bambury
2020/04/16 全球购物
党员批评与自我批评
2014/02/12 职场文书
求职个人评价范文
2014/04/09 职场文书
慰问信模板
2015/02/14 职场文书
初三化学教学反思
2016/02/22 职场文书
廉洁自律承诺书2016
2016/03/25 职场文书
日本动漫十大公认神作:第五现已全网禁播,《死亡笔记》在榜
2022/03/18 日漫