python多線程http下載實現樣本_python

來源:互聯網
上載者:User

測試平台 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)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.