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网络编程之数据传输UDP实例分析
May 20 Python
Python中类型检查的详细介绍
Feb 13 Python
Python装饰器用法示例小结
Feb 11 Python
浅谈Python中的私有变量
Feb 28 Python
Python批量合并有合并单元格的Excel文件详解
Apr 05 Python
tensorflow学习笔记之mnist的卷积神经网络实例
Apr 15 Python
pygame游戏之旅 载入小车图片、更新窗口
Nov 20 Python
对Python Class之间函数的调用关系详解
Jan 23 Python
对Python w和w+权限的区别详解
Jan 23 Python
Numpy将二维数组添加到空数组的实现
Dec 05 Python
python实现经纬度采样的示例代码
Dec 10 Python
解决selenium+Headless Chrome实现不弹出浏览器自动化登录的问题
Jan 09 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分页显示制作详细讲解
2008/11/19 PHP
php array_map array_multisort 高效处理多维数组排序
2009/06/11 PHP
高性能PHP框架Symfony2经典入门教程
2014/07/08 PHP
Zend Framework实现将session存储在memcache中的方法
2016/03/22 PHP
ThinkPHP使用getlist方法实现数据搜索功能示例
2017/05/08 PHP
firefox 和 ie 事件处理的细节,研究,再研究 书写同时兼容ie和ff的事件处理代码
2007/04/12 Javascript
类似php的js数组的in_array函数自定义方法
2013/12/27 Javascript
javascript中的括号()用法小结
2014/04/14 Javascript
jquery图片切换实例分析
2015/04/15 Javascript
学习使用grunt来打包JavaScript和CSS程序的教程
2016/01/04 Javascript
微信小程序 获取当前地理位置和经纬度实例代码
2016/12/05 Javascript
Jquery Easyui菜单组件Menu使用详解(15)
2016/12/18 Javascript
令按钮悬浮在(手机)页面底部的实现方法
2017/05/02 Javascript
nodejs操作mysql实现增删改查的实例
2017/05/28 NodeJs
vue中appear的用法
2017/08/17 Javascript
浅谈webpack下的AOP式无侵入注入
2017/11/12 Javascript
js将当前时间格式化为 年-月-日 时:分:秒的实现代码
2018/01/20 Javascript
微信端调取相册和摄像头功能,实现图片上传,并上传到服务器
2019/05/16 Javascript
vue动态配置模板 'component is'代码
2019/07/04 Javascript
Vue实现跑马灯效果
2020/05/25 Javascript
Python函数中定义参数的四种方式
2014/11/30 Python
python使用PythonMagick将jpg图片转换成ico图片的方法
2015/03/26 Python
python构建自定义回调函数详解
2017/06/20 Python
python中的协程深入理解
2019/06/10 Python
Python Opencv中用compareHist函数进行直方图比较对比图片
2020/04/07 Python
mac安装python3后使用pip和pip3的区别说明
2020/09/01 Python
中国网上药店领导者:1药网
2017/02/16 全球购物
革命先烈的英雄事迹材料
2014/02/15 职场文书
2014年医院后勤工作总结
2014/12/06 职场文书
教师工作表现自我评价
2015/03/05 职场文书
春风化雨观后感
2015/06/11 职场文书
大学运动会通讯稿
2015/07/18 职场文书
礼仪培训心得体会
2016/01/22 职场文书
民事调解协议书
2016/03/21 职场文书
2016年小学“公民道德宣传日”活动总结
2016/04/01 职场文书
java版 联机五子棋游戏
2022/05/04 Java/Android