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使用django获取用户IP地址的方法
May 11 Python
定制FileField中的上传文件名称实例
Aug 23 Python
python分布式环境下的限流器的示例
Oct 26 Python
K-近邻算法的python实现代码分享
Dec 09 Python
Python 利用scrapy爬虫通过短短50行代码下载整站短视频
Oct 29 Python
wxPython绘图模块wxPyPlot实现数据可视化
Nov 19 Python
python psutil监控进程实例
Dec 17 Python
python代码如何实现余弦相似性计算
Feb 09 Python
Pycharm插件(Grep Console)自定义规则输出颜色日志的方法
May 27 Python
Python爬虫JSON及JSONPath运行原理详解
Jun 04 Python
基于PyTorch的permute和reshape/view的区别介绍
Jun 18 Python
Python 程序员必须掌握的日志记录
Aug 17 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 fsockopen中多线程问题的解决办法[翻译]
2011/11/09 PHP
Yii框架获取当前controlle和action对应id的方法
2014/12/03 PHP
php数组转成json格式的方法
2015/03/09 PHP
PHP常用的小程序代码段
2015/11/14 PHP
laravel创建类似ThinPHP中functions.php的全局函数
2016/11/26 PHP
PHP开发中csrf攻击的简单演示和防范
2017/05/07 PHP
Gambit vs ForZe BO3 第二场 2.13
2021/03/10 DOTA
在VS2008中使用jQuery智能感应的方法
2010/12/30 Javascript
解析使用JS 清空File控件的路径值
2013/07/08 Javascript
获取3个数组不重复的值的具体实现
2013/12/30 Javascript
win7下安装配置node.js+express开发环境
2015/12/06 Javascript
原生JS实现平滑回到顶部组件
2016/03/16 Javascript
jquery实现图片上传前本地预览功能
2016/05/10 Javascript
js中获取jsp表单中radio类型的值简单实例
2016/08/15 Javascript
Javascript 实现计算器时间功能详解及实例(二)
2017/01/08 Javascript
jquery实现左右滑动式轮播图
2017/03/02 Javascript
NodeJs的fs读写删除移动监听
2017/04/28 NodeJs
当vue路由变化时,改变导航栏的样式方法
2018/08/22 Javascript
Vue SSR 即时编译技术的实现
2020/05/06 Javascript
原生js实现照片墙效果
2020/10/13 Javascript
python爬虫入门教程--利用requests构建知乎API(三)
2017/05/25 Python
Python构建XML树结构的方法示例
2017/06/30 Python
python实现AES加密与解密
2019/03/28 Python
Python 线程池用法简单示例
2019/10/02 Python
详解Python实现进度条的4种方式
2020/01/15 Python
Fashion Eyewear美国:英国线上设计师眼镜和太阳镜的零售商
2016/08/15 全球购物
阿迪达斯奥地利官方商城:adidas.at
2016/10/16 全球购物
乌克兰设计师和品牌的服装:Love&Live
2020/04/14 全球购物
如何写出高质量、高性能的MySQL查询
2014/11/17 面试题
就业推荐自我鉴定
2013/10/06 职场文书
《再见了,亲人》教学反思
2014/02/26 职场文书
美国留学经济担保书
2014/05/20 职场文书
网络文明传播志愿者活动方案
2014/08/20 职场文书
竞聘自述材料
2014/08/25 职场文书
离婚案件原告代理词
2015/05/23 职场文书
React列表栏及购物车组件使用详解
2021/06/28 Javascript