ホームページ  >  記事  >  バックエンド開発  >  Python マルチスレッド http ダウンロードの実装例

Python マルチスレッド http ダウンロードの実装例

WBOY
WBOYオリジナル
2016-06-16 08:45:521493ブラウズ

测试平台 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 # ファイルのサイズを取得します
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
using use使用する 使用する through ’ s ’ s through out’s out’s ’ through ’ s ’ through ‐ to ‐ ‐ ‐ ,を通じて
# plist の t に対してレンガの移動を開始します
:

t.start()


# すべてのスレッドが終了するまで待ちます
for t in plist:

t.join()


# 終了したらファイルオブジェクトを忘れずに閉じてください
fobj.close()

print 'ダウンロードが完了しました!'


if __name__ == '__main__':
url = 'http://192.168.1.2:8082/downloads/10M.zip'

main(url=url, thread=10, save_file='test .iso'、バッファ=4096)



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。