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实现3行代码解简单的一元一次方程
Aug 18 Python
Python中的赋值、浅拷贝、深拷贝介绍
Mar 09 Python
深入讨论Python函数的参数的默认值所引发的问题的原因
Mar 30 Python
Python连接MySQL并使用fetchall()方法过滤特殊字符
Mar 13 Python
机器学习经典算法-logistic回归代码详解
Dec 22 Python
python书籍信息爬虫实例
Mar 19 Python
Python3网络爬虫中的requests高级用法详解
Jun 18 Python
python实现串口自动触发工作的示例
Jul 02 Python
Django框架之中间件MiddleWare的实现
Dec 30 Python
Python动态导入模块:__import__、importlib、动态导入的使用场景实例分析
Mar 30 Python
Python实现Word文档转换Markdown的示例
Dec 22 Python
Python中lru_cache的使用和实现详解
Jan 25 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 运行效率总结(提示程序速度)
2009/11/26 PHP
兼容性最强的PHP生成缩略图的函数代码(修改版)
2011/01/18 PHP
apache配置虚拟主机的方法详解
2013/06/17 PHP
采用header定义为文件然后readfile下载(隐藏下载地址)
2014/01/31 PHP
php CI框架插入一条或多条sql记录示例
2014/07/29 PHP
PHP实现多关键字加亮功能
2016/10/21 PHP
使用PHP连接数据库_实现用户数据的增删改查的整体操作示例
2017/09/01 PHP
Jquery公告滚动+AJAX后台得到数据
2011/04/14 Javascript
JS Replace 全部替换字符的用法小结
2013/12/24 Javascript
jQuery事件绑定与解除绑定实现方法
2015/04/15 Javascript
原生js和jQuery实现淡入淡出轮播效果
2015/12/25 Javascript
javascript实现全角转半角的方法
2016/01/23 Javascript
Vue.js开发环境搭建
2016/11/10 Javascript
纯js三维数组实现三级联动效果
2017/02/07 Javascript
简单实现AngularJS轮播图效果
2020/04/10 Javascript
通过命令行生成vue项目框架的方法
2017/07/12 Javascript
Angular.js中angular-ui-router的简单实践
2017/07/18 Javascript
使用vuepress搭建静态博客的示例代码
2019/02/14 Javascript
vue实现多级菜单效果
2019/10/19 Javascript
将string类型的数据类型转换为spark rdd时报错的解决方法
2019/02/18 Python
python利用tkinter实现屏保
2019/07/30 Python
Django使用uwsgi部署时的配置以及django日志文件的处理方法
2019/08/30 Python
python GUI库图形界面开发之PyQt5控件数据拖曳Drag与Drop详细使用方法与实例
2020/02/27 Python
CSS3使用多列制作瀑布流
2016/05/10 HTML / CSS
CSS3实现苹果手机解锁的字体闪亮效果示例
2021/01/05 HTML / CSS
使用html5实现表格实现标题合并的实例代码
2019/05/13 HTML / CSS
Mytheresa中国官网:德国时尚奢侈品商城
2017/08/04 全球购物
2014年教师培训的自我评价
2014/01/03 职场文书
经典婚礼主持开场白
2014/03/13 职场文书
幼儿园新年寄语
2014/04/03 职场文书
幼儿园师德演讲稿
2014/05/06 职场文书
大学专科自荐信
2014/06/17 职场文书
房屋租赁意向书范本
2015/05/09 职场文书
校运会通讯稿
2015/07/18 职场文书
2016年共产党员公开承诺书
2016/03/24 职场文书
python中sys模块的介绍与实例
2021/04/17 Python