python多线程http下载实现示例
发布时间:2023-12-03 00:15:34
测试平台 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 3.10上安装pyqt5前言首先,看一下自己电脑上的python的版本,网上有太多乱七八糟的教程,啥也不说就硬教,跟着做的话就
- 本文向大家分享23种JavaScript提高执行效率的小技巧、最佳实践等非常实用的内容。当然JavaScript的实用技巧不止这些,还有很多
- 默认值可以很方便众所周知,在Python中如果访问字典中不存在的键,会引发KeyError异常(JavaScript中如果对象中不存在某个属
- 近日在月影的blog上找到一段代码。看了老半天没明白什么意思,倍受打击!不死心,于是仔细分析思考了好几次,才明白过来这段函数的意义。js果然
- 完成这个小球的完全弹性碰撞游戏灵感来自于:下面是我花了一周下班时间所编写的一个小球完全弹性碰撞游戏:游戏初始化状态:最下面的游标和修改小球的
- PyMysql使用详解在编写小脚本时,PyMysql是快速连接并操作数据库的一个不错选择。安装pip3 install PyMysql# 可
- uWSGI是一个Web应用服务器,它具有应用服务器,代理,进程管理及应用监控等功能。它支持WSGI协议,同时它也支持自有的uWSGI协议,该
- 天天敲代码的朋友,有没有想过代码也可以变得很酷炫又浪漫?今天就教大家用Python模拟出绽放的烟花,工作之余也可以随时让程序为自己放一场烟花
- 这篇文章主要介绍了基于python读取.mat文件并取出信息,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 最后罗嗦一句,本人录入这篇文章用的机器上没有 ASP 环境,所以提供的代码未能进行测试,对这一点本人深表歉意。如果大家发现了代码中的任何问题
- 滑动验证码介绍本篇涉及到的验证码为滑动验证码,不同于极验证,本验证码难度略低,需要的将滑块拖动到矩形区域右侧即可完成。这类验证码不常见了,官
- 如何使用快捷键按出代码提示框更新win10,发现可以改取消ctrl + space快捷键的占用了!!!我们在平时写代码的时候难免会出现敲错字
- Data URIData URI是由RFC 2397定义的一种把小文件直接嵌入文档的方案。通过如下语法就可以把小文件变成指定编码直接嵌入到页
- 前言Python包含6种内置的序列:列表、元组、字符串 、Unicode字符串、buffer对象、xrange对象。在序列中的每个元素都有自
- 为了组织search线的设计师交流会,特地去准备了一些资料。《SERP 2010》是其中一个,但是由于时间关系没有进行讨论。原著是英文报告,
- 奥运来了,三大门户网站都加上了奥运主题。加上下面代码你的网站也拥有奥运主题了:<style type="text/
- github指路作业要求友情提示ldw老师给の友情提示(虽然感觉也还好/dbq其实还挺有用的)课上讲的例子是图片展示器(能够实现打开图片+镜
- 以下为在asp中增加一个sql server2000用户函数,并为建立一个数据库,给他dbo的权限。注意:sql server的验证方式不要
- 阅读上一章:Chapter 4 引用互动性一直是互联网的重点,让使用者与网站能够交换信息,彼此沟通.表单使我们能够有组织的,使用同一方式的从