Ricky Hao

Python 之 多线程下载

昨天我们实现了Python的简易文件下载,但是那样速度太慢。
所以,今天我简单的实现了下Python下的多线程下载。

首先,让我们知道普通单线程的大概流程:

绘图1.jpg

然后,对于多线程下载,是这样的:
绘图2.jpg

在HTTP请求头中,有一个字段叫做Range
这个字段用来将数据分割,每次请求可以请求不同部分的的数据,将这些数据同时下载就是多线程下载了。

那么,我们就需要两个东西:
一、HTTP头的构造
二、Python多线程编程

一、HTTP头的构造
一般的HTTP头是下图这样的:
QQ图片20151025173309.png

而我们要构造的带Range的头是这样的:

QQ截图20151025173510.png

这其中的区别就是在Range字段。

在Python里呢,我们可以用urllib.request库中的两个函数来增加Range字段:

import urllib.request;                        #导入urllib.request库

url='http://www.example.com/1.txt';
req=urllib.request.Request(url);            #得到该URL的请求HTTP头
req.add_header('Range','bytes=0-102400');    #在该请求头中,加入Range字段,并写出数据范围
u=urllib.request.urlopen(req);                #用修改好的请求头打开链接

这样,我们就直到如何分片请求数据了。

二、Python简易多线程编程
下载线程的编写大概就像下面这样:

import threading;
class Download_Thread(threading.Thread):        #用class类封装threading.Thread类型的Download_Thread对象
    """This is a Thread of Downloading"""
    def __init__(self, ):                        #定义构造方法
        super(Download_Thread, self).__init__();
        self.url = url;
    def run():
        #以下写分片下载的代码        

而开始一个新下载线程我们可以这样:

Download_Thread(#需要的参数).start();

这样就可以启动一个下载线程,在执行完start()函数内容之后,线程关闭(start()函数就是调用类中的run()函数)。

当然,有了这些还不够。你需要有一个函数能够来控制线程。
比如分配每个线程所要下载的数据范围;

得到每个线程返回的数据并将其插入文件中。

关于插入文件,我们可以这样:

f=open('1.txt','a+');
f.seek(#插入位置);            #这里的插入位置指从文件起始的第n个字节处开始
f.write(data);

好了,现在我们可以写一个简易的多线程下载程序了:

import urllib.request,threading;
class Download_Thread(threading.Thread):
    """Download"""
    def __init__(self, url,start_bit,end_bit,f):    #构造方法,形参
        super(Download_Thread, self).__init__();
        self.url = url;
        self.start_bit = start_bit;
        self.end_bit=end_bit;
        self.f=f;

    def run():
        req = urllib.request.Request(url);            #得到请求头
        req.add_header('Range','bytes='+str(self.start_bit)+'-'+str(self.end_bit));
        u=urllib.request.urlopen(url);                #上面是添加Range字段
        
        self.data=[];                                #下载开始
        block=8192;
        while True:
            buf=u.read(block);
            if(len(buf)==0):
                break;
            self.data.append(buf);
        Insert();                                    #调用插入文件函数
        

    def Insert():
        self.f.seek(self.start_bit);                #文件寻址到start_bit
        i=0;
        while(i
点赞
  1. xiao说道:

    博主 你的博客小人物怎么实现的

回复 xiao 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据