ホームページ  >  記事  >  バックエンド開発  >  非同期コルーチン開発の実践: 大きなファイルのアップロードおよびダウンロードの速度の最適化

非同期コルーチン開発の実践: 大きなファイルのアップロードおよびダウンロードの速度の最適化

PHPz
PHPzオリジナル
2023-12-17 12:50:28791ブラウズ

非同期コルーチン開発の実践: 大きなファイルのアップロードおよびダウンロードの速度の最適化

非同期コルーチン開発の実践: 大きなファイルのアップロードおよびダウンロードの速度の最適化

インターネットの発展と普及に伴い、ファイルの送信が標準になりました。しかし、転送されるファイルがますます大きくなると、従来のファイルのアップロードおよびダウンロード方法では多くの困難に直面するようになります。大きなファイルの転送速度を最適化し、ユーザー エクスペリエンスを向上させるために、非同期コルーチンを通じて実装できます。この記事では、非同期コルーチン テクノロジを使用して大きなファイルのアップロードおよびダウンロードの速度を最適化する方法を共有し、具体的なコード例を示します。

1. 非同期コルーチン テクノロジの概要

非同期コルーチンは本質的にプログラミング モデルです。その特徴は、ブロッキングが発生した場合、現在のスレッドの制御を即座に解放し、他のタスクに制御を渡して実行を継続し、ブロッキングが終了するまで待ってから実行に戻ることで、より良い結果を得るために複数のタスク間の切り替えを実現することです。 . 効率的な処理効果。

一般的な非同期コルーチン テクノロジには、Python の asyncio、Node.js の Callback および Promise などが含まれます。言語やテクノロジが異なれば実装方法も異なりますが、基本的にはすべて、コンピュータ リソースをより有効に活用して同時実行性と処理効率を向上させるように設計されています。

2. 大きなファイルのアップロード速度を最適化する

  1. チャンクアップロードを使用する

大きなファイルをアップロードする場合は、ファイル全体を一度にサーバーに転送しますこれにより、必然的にネットワークの混雑と通信速度の低下が発生します。この問題を回避するには、大きなファイルを複数のチャンクに分けてアップロードすることができます。各チャンクは独立したデータ パケットであり、並行してアップロードすることでアップロードを高速化できます。

非同期コルーチン テクノロジを使用すると、ブロック アップロードを簡単に実装し、複数のデータ ブロックを並行して送信して、より効率的なアップロード操作を実現できます。以下は具体的なコードの実装です。

import aiohttp
import asyncio

async def upload_chunk(session, url, file, offset, size):
    headers = {'Content-Length': str(size), 'Content-Range': f'bytes {offset}-{offset+size-1}/{file_size}'}
    data = file.read(size)
    async with session.put(url, headers=headers, data=data) as resp:
        return await resp.json()

async def upload_file_with_chunks(session, url, file):
    file_size = os.path.getsize(file.name)
    chunk_size = 1024 * 1024 * 5 #每块数据的大小为5MB
    offset = 0
    tasks = []
    while offset < file_size:
        size = chunk_size if offset+chunk_size < file_size else file_size-offset
        tasks.append(upload_chunk(session, url, file, offset, size))
        offset += size
    return await asyncio.gather(*tasks)

async def main():
    async with aiohttp.ClientSession() as session:
        url = 'http://example.com/upload'
        file = open('large_file.mp4', 'rb')
        result = await upload_file_with_chunks(session, url, file)
        print(result)

asyncio.run(main())

このコードでは、ファイル全体をサイズ 5MB のデータ ブロックに分割し、asyncio.gather() メソッドを使用して各データをアップロードするタスクを同時に実行します。ブロックしてアップロードを高速化します。チャンクアップロードの考え方はファイルのダウンロードにも当てはまりますので、詳しくは次のセクションをご覧ください。

  1. マルチスレッド アップロード

マルチスレッド アップロードの使用に加えて、マルチスレッドを使用して大きなファイルをアップロードすることもできます。マルチスレッドを使用すると、コンピュータのマルチコア リソースを最大限に活用できるため、ファイルのアップロードが高速化されます。以下は具体的なコードの実装です。

import threading
import requests

class MultiPartUpload(object):
    def __init__(self, url, file_path, num_thread=4):
        self.url = url
        self.file_path = file_path
        self.num_thread = num_thread
        self.file_size = os.path.getsize(self.file_path)
        self.chunk_size = self.file_size//num_thread
        self.threads = []
        self.lock = threading.Lock()

    def upload(self, i):
        start = i * self.chunk_size
        end = start + self.chunk_size - 1
        headers = {"Content-Range": "bytes %s-%s/%s" % (start, end, self.file_size),
                   "Content-Length": str(self.chunk_size)}
        data = open(self.file_path, 'rb')
        data.seek(start)
        resp = requests.put(self.url, headers=headers, data=data.read(self.chunk_size))
        self.lock.acquire()
        print("Part %d status: %s" % (i, resp.status_code))
        self.lock.release()

    def run(self):
        for i in range(self.num_thread):
            t = threading.Thread(target=self.upload, args=(i,))
            self.threads.append(t)
        for t in self.threads:
            t.start()

        for t in self.threads:
            t.join()

if __name__ == '__main__':
    url = 'http://example.com/upload'
    file = 'large_file.mp4'
    uploader = MultiPartUpload(url, file)
    uploader.run()

このコードでは、Python 標準ライブラリの threading モジュールを使用してマルチスレッド アップロードを実装します。ファイル全体を複数のデータ ブロックに分割し、各スレッドがブロックの 1 つをアップロードする責任を負うため、同時アップロードが実現します。ロック メカニズムを使用して、同時アップロード中のスレッドの安全性を保護します。

3. 大きなファイルのダウンロード速度の最適化

アップロードに加えて、大きなファイルのダウンロードも非常に一般的な要件であり、最適化は非同期コルーチンによっても実現できます。

  1. 一括ダウンロード

チャンク アップロードと同様、チャンク ダウンロードではファイル全体がいくつかのチャンクに分割され、各チャンクが個別にダウンロードされ、複数のデータ チャンクが並行して送信されます。 . これによりダウンロードが高速化されます。具体的なコードの実装は次のとおりです。

import aiohttp
import asyncio
import os

async def download_chunk(session, url, file, offset, size):
    headers = {'Range': f'bytes={offset}-{offset+size-1}'}
    async with session.get(url, headers=headers) as resp:
        data = await resp.read()
        file.seek(offset)
        file.write(data)
        return len(data)

async def download_file_with_chunks(session, url, file):
    async with session.head(url) as resp:
        file_size = int(resp.headers.get('Content-Length'))
        chunk_size = 1024 * 1024 * 5 #每块数据的大小为5MB
        offset = 0
        tasks = []
        while offset < file_size:
            size = chunk_size if offset+chunk_size < file_size else file_size-offset
            tasks.append(download_chunk(session, url, file, offset, size))
            offset += size
        return await asyncio.gather(*tasks)

async def main():
    async with aiohttp.ClientSession() as session:
        url = 'http://example.com/download/large_file.mp4'
        file = open('large_file.mp4', 'wb+')
        await download_file_with_chunks(session, url, file)

asyncio.run(main())

このコードでは、aiohttp ライブラリを使用して、非同期コルーチンの並列ダウンロードを実行します。同様に、ファイル全体を 5MB のデータ ブロックに分割し、asyncio.gather() メソッドを使用して各データ ブロックを同時にダウンロードするタスクを実行し、ファイルのダウンロードを高速化します。

  1. マルチスレッド ダウンロード

チャンクでダウンロードするだけでなく、マルチスレッド ダウンロードを使用して大きなファイルをダウンロードすることもできます。具体的なコード実装は次のとおりです。

import threading
import requests

class MultiPartDownload(object):
    def __init__(self, url, file_path, num_thread=4):
        self.url = url
        self.file_path = file_path
        self.num_thread = num_thread
        self.file_size = requests.get(self.url, stream=True).headers.get('Content-Length')
        self.chunk_size = int(self.file_size) // self.num_thread
        self.threads = []
        self.lock = threading.Lock()

    def download(self, i):
        start = i * self.chunk_size
        end = start + self.chunk_size - 1 if i != self.num_thread - 1 else ''
        headers = {"Range": "bytes=%s-%s" % (start, end)}
        data = requests.get(self.url, headers=headers, stream=True)
        with open(self.file_path, 'rb+') as f:
            f.seek(start)
            f.write(data.content)
        self.lock.acquire()
        print("Part %d Downloaded." % i)
        self.lock.release()

    def run(self):
        for i in range(self.num_thread):
            t = threading.Thread(target=self.download, args=(i,))
            self.threads.append(t)
        for t in self.threads:
            t.start()

        for t in self.threads:
            t.join()

if __name__ == '__main__':
    url = 'http://example.com/download/large_file.mp4'
    file = 'large_file.mp4'
    downloader = MultiPartDownload(url, file)
    downloader.run()

このコードでは、Python 標準ライブラリの threading モジュールも使用して、マルチスレッド ダウンロードを実装します。ファイル全体が複数のデータ ブロックに分割され、各スレッドがブロックの 1 つをダウンロードする責任を負うため、同時ダウンロードが実現されます。ロック メカニズムは、同時ダウンロード中のスレッドの安全性を保護するためにも使用されます。

4. 概要

この記事では、非同期コルーチン テクノロジを使用して、大きなファイルのアップロードおよびダウンロードの速度を最適化する方法を紹介します。アップロードとダウンロードの処理をブロック化して並列処理することで、ファイル転送の効率を大幅に向上します。非同期コルーチン、マルチスレッド、分散システムなどの分野に幅広く応用できます。この記事がお役に立てば幸いです!

以上が非同期コルーチン開発の実践: 大きなファイルのアップロードおよびダウンロードの速度の最適化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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