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 相关文章推荐
Python3中条件控制、循环与函数的简易教程
Nov 21 Python
Python学习笔记之集合的概念和简单使用示例
Aug 22 Python
python 中xpath爬虫实例详解
Aug 26 Python
ipad上运行python的方法步骤
Oct 12 Python
Python动态声明变量赋值代码实例
Dec 30 Python
Django-rest-framework中过滤器的定制实例
Apr 01 Python
python可以用哪些数据库
Jun 22 Python
图解Python中深浅copy(通俗易懂)
Sep 03 Python
python实现代码审查自动回复消息
Feb 01 Python
Python 实现劳拉游戏的实例代码(四连环、重力四子棋)
Mar 03 Python
pytorch分类模型绘制混淆矩阵以及可视化详解
Apr 07 Python
python turtle绘图
May 04 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 $_SERVER当前完整url的写法
2009/11/12 PHP
PHP文件系统管理(实例讲解)
2017/09/19 PHP
通用javascript脚本函数库 方便开发
2009/10/13 Javascript
JavaScript CSS修改学习第一章 查找位置
2010/02/19 Javascript
js给dropdownlist添加选项的小例子
2013/03/04 Javascript
改变隐藏的input中value的值代码
2013/12/30 Javascript
查找Oracle高消耗语句的方法
2014/03/22 Javascript
NodeJS制作爬虫全过程(续)
2014/12/22 NodeJs
JS中如何比较两个Json对象是否相等实例代码
2016/07/13 Javascript
AngularJS页面传参的5种方式
2017/04/01 Javascript
Angular2使用Augury来调试Angular2程序
2017/05/21 Javascript
Vue项目组件化工程开发实践方案
2018/01/09 Javascript
jQuery实现的鼠标响应缓冲动画效果示例
2018/02/13 jQuery
vue中锚点的三种方法
2018/07/06 Javascript
js+html5 canvas实现ps钢笔抠图
2019/04/28 Javascript
vue路由插件之vue-route
2019/06/13 Javascript
vue使用自定义事件的表单输入组件用法详解【日期组件与货币组件】
2020/06/01 Javascript
[02:41]DOTA2亚洲邀请赛小组赛第三日 赛事回顾
2015/02/01 DOTA
python 参数列表中的self 显式不等于冗余
2008/12/01 Python
Python多进程机制实例详解
2015/07/02 Python
python 默认参数问题的陷阱
2016/02/29 Python
详细解读tornado协程(coroutine)原理
2018/01/15 Python
Python错误处理操作示例
2018/07/18 Python
python读取Kafka实例
2019/12/23 Python
CentOS 7如何实现定时执行python脚本
2020/06/24 Python
哪种Python框架适合你?简单介绍几种主流Python框架
2020/08/04 Python
matplotlib制作雷达图报错ValueError的实现
2021/01/05 Python
一个基于canvas的移动端图片编辑器的实现
2020/10/28 HTML / CSS
美国休闲服装品牌:J.Crew Factory
2017/03/04 全球购物
普通大学毕业生自荐信范文
2014/02/23 职场文书
志愿者活动总结报告
2014/06/27 职场文书
安全资料员岗位职责范本
2014/06/28 职场文书
先进党支部事迹材料
2014/12/24 职场文书
外科护士长工作总结
2015/08/12 职场文书
《亲亲我的妈妈》观后感(3篇)
2019/09/26 职场文书
html实现弹窗的实例
2021/06/09 HTML / CSS