Amalan pembangunan coroutine tak segerak: mengoptimumkan kelajuan memuat naik dan memuat turun fail besar
Dengan pembangunan dan pempopularan Internet, penghantaran fail telah menjadi kebiasaan. Tetapi apabila fail yang dipindahkan menjadi lebih besar dan lebih besar, kaedah memuat naik dan memuat turun fail tradisional akan menghadapi banyak kesukaran. Untuk mengoptimumkan kelajuan penghantaran fail besar dan meningkatkan pengalaman pengguna, kami boleh melaksanakannya melalui coroutine tak segerak. Artikel ini akan berkongsi cara menggunakan teknologi coroutine tak segerak untuk mengoptimumkan muat naik dan kelajuan muat turun fail besar serta menyediakan contoh kod khusus.
1. Pengenalan kepada teknologi coroutine tak segerak
Coroutine tak segerak pada asasnya ialah model pengaturcaraan. Cirinya ialah apabila penyekatan berlaku, ia boleh segera melepaskan kawalan benang semasa, menyerahkan kawalan kepada tugas lain untuk meneruskan pelaksanaan, dan tunggu sehingga penyekatan selesai sebelum kembali ke pelaksanaan, dengan itu merealisasikan pertukaran antara pelbagai tugas untuk dicapai hasil yang lebih baik.
Teknologi coroutine tak segerak biasa termasuk asyncio dalam Python, Callback dan Promise dalam Node.js, dsb. Bahasa dan teknologi yang berbeza mungkin mempunyai kaedah pelaksanaan yang berbeza, tetapi pada asasnya semuanya direka untuk menggunakan sumber komputer dengan lebih baik untuk meningkatkan keselarasan dan kecekapan pemprosesan.
2. Optimumkan kelajuan muat naik fail yang besar
Apabila memuat naik fail besar, pemindahan keseluruhan fail ke pelayan pada satu masa pasti akan menyebabkan kesesakan rangkaian dan kelajuan penghantaran yang perlahan. Untuk mengelakkan masalah ini, fail besar boleh dimuat naik ke dalam beberapa ketulan Setiap ketulan adalah paket data bebas dan boleh dimuat naik secara selari untuk mempercepatkan muat naik.
Menggunakan teknologi coroutine tak segerak, anda boleh melaksanakan muat naik bongkah dan menghantar berbilang ketulan data secara selari untuk mencapai operasi muat naik yang lebih cekap. Berikut ialah pelaksanaan kod khusus.
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())
Dalam kod ini, kami membahagikan keseluruhan fail kepada blok data 5MB, dan kemudian menggunakan kaedah asyncio.gather()
untuk melaksanakan tugas memuat naik setiap blok data secara serentak untuk mempercepatkan muat naik. kelajuan. Idea muat naik potongan juga terpakai untuk muat turun fail Sila lihat bahagian seterusnya untuk butiran. asyncio.gather()
方法将上传各个数据块的任务并发执行,以加快上传速度。分块上传的思路也同样适用于文件下载,具体请看下一节内容。
除了使用分块上传,还可以使用多线程的方式来实现大文件的上传操作。使用多线程可以更充分地利用计算机的多核资源,从而加速文件上传的速度。下面是具体的代码实现。
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
模块来实现多线程上传。将整个文件分成多个数据块,每个线程负责上传其中的一块,从而实现并发上传。使用锁机制来保护并发上传过程中的线程安全。
三、优化大文件下载的速度
除了上传,下载大文件同样是一个很常见的需求,同样可以通过异步协程来实现优化。
和分块上传类似,分块下载将整个文件划分成若干块,每一块独立下载,并行传输多个块数据,从而加快下载速度。具体的代码实现如下:
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()
方法将下载各个数据块的任务并发执行,加快文件下载速度。
除了分块下载,还可以使用多线程下载的方式来实现大文件的下载操作。具体的代码实现如下:
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
Selain menggunakan muat naik chunked, anda juga boleh menggunakan multi-threading untuk memuat naik fail besar. Menggunakan multi-threading boleh menggunakan sepenuhnya sumber berbilang teras komputer anda, dengan itu mempercepatkan muat naik fail. Berikut ialah pelaksanaan kod khusus.
rrreee🎜Dalam kod ini, kami menggunakan modulaiohttp
untuk melaksanakan muat turun selari coroutine tak segerak. Begitu juga, bahagikan keseluruhan fail kepada blok data 5MB, dan kemudian gunakan kaedah asyncio.gather()
untuk melaksanakan tugas memuat turun setiap blok data secara serentak untuk mempercepatkan muat turun fail. 🎜Atas ialah kandungan terperinci Amalan Pembangunan Coroutine Asynchronous: Mengoptimumkan Kelajuan Memuat Naik dan Memuat Turun Fail Besar. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!