ここではアルゴリズム (分岐アルゴリズム) に関与します。
私が最近始めた広告プラットフォームプロジェクトでは、顧客が私の会社の信頼性を証明するために自己認証されたビデオを提供する必要があるためです。
現在、ビデオの解像度はますます高くなっており、これに伴ってビデオ メモリが膨大になることがよくあります。数分のビデオでも数ギガバイトのメモリが必要です。通常のアップロード方法では絶対に不可能です。ファイルは大きく、速度が遅いため、お客様のエクスペリエンスに影響を及ぼします。この問題を解決するために、大きなファイルを n 個の小さなファイルに分割してアップロードする分割アップロード方法を採用し、送信効率を高速化しました。
ここではアルゴリズム (分岐アルゴリズム) に関与します。
部分アップロードの概念は、分割統治アルゴリズムです。分割統治し、大きな問題を複数の小さな問題に変換して解決します。!
フロントエンドシャーディング
まずフロントエンドで断片化を行い、断片化がバックエンドに送信されます。ここでは vue3 を使用し、UI フレームワークは ant-desgin、使用されるコントロールは a-upload です。ユーザーはアップロードをクリックして、アップロードするファイル。
この時点で、ファイルの名前とサイズを取得し、必要なフラグメントのサイズを定義できます。ここで判断を書き、アップロードするファイルのサイズを伝え、ファイルのサイズを定義できます。ファイルが小さすぎる場合は、リソースを消費する断片化の必要はありません。このとき余りが出るので合計個数が得られるので、Math.ceilの四捨五入メソッドを使って合計個数を求めます。この時点で、各スライスの開始位置と終了位置を取得し、ファイルをスライス単位でスライスして、処理のためにバックエンドに送信できます。
//上传方法
handleChange:function(file){
//获取文件大小 1024字节 1kb
console.log(file.file)
var size = file.file.size
this.size = size
// this.filename = file.file.name
//定义分片大小
var shardSize = 1024 * 100
//总片数
//向上取整
this.shardCount = Math.ceil(size / shardSize)
//切片操作
for (var i=0;i<this.shardCount; ++i){
//开始位置
var start = i * shardSize
//结束位置
var end = Math.min(size,start+shardSize)
//切片
var shardfile = file.file.slice(start,end)
this.pushshard(shardfile,file.file.name,i)
}
},
ここまでで、フロントエンドのシャーディング ロジックが完成しました。
バックエンドは非同期で書き込みます
バックエンドではPythonのtronadoフレームワークを使って非同期書き込みを行っているのですが、同期書き込みによるブロッキングを避けるためにaiofilesライブラリをインストールしてtornadoの非同期機構と連携させて書き込みの効率を上げています。
ここで、バックエンドはファイル エンティティ、ファイル名、およびフラグを取得し、最初にファイル エンティティを指定されたパスに非同期で書き込み、次にそれを読み取り、順番にマージします。ファイル操作についてはあまり詳しく説明しません。文法はすべて修正されており、ロジックはありません。次のコードが示しています。自分で見てください。
# 分片上传
class SliceUploadHandler(BaseHandler):
#合并分片
async def put(self):
filename = self.get_argument("filename",None)
count = 0
size = self.get_argument("size",None)
try:
filesize = os.path.getsize("./static/upload/{}".format(filename))
except Exception as e:
print(str(e))
filesize = 0
if int(size) != filesize:
#异步打开文件句柄
async with aiofiles.open("./static/upload/{}".format(filename),"ab") as file:
while True:
try:
#读取分片
shard_file = open("./static/upload/{}_{}".format(filename,count),"rb")
#异步写入
await file.write(shard_file.read())
#手动关闭句柄
shard_file.close()
except Exception as e:
print(str(e))
break
count = count + 1
self.finish({"errcode":0,"msg":"合并完毕"})
# 分片文件接收
async def post(self):
#接收分片实体
file = self.request.files["file"][0]
#获取下标
count = self.get_argument("count",None)
#获取文件名
filename = self.get_argument("filename",None)
#获取文件内容
content = file["body"]
#异步写入
async with aiofiles.open("./static/upload/{}_{}".format(filename,count),"wb") as file:
#异步
await file.write(content)
self.finish({"errcode":0,"msg":"分片上传成功"})
ここまではバックエンドのデバッグでしたが、実際の大容量ファイル転送のシナリオでは、ネットワークなどの要因により断片化タスクが中断される可能性があり、その際にはダウングレードしてバックエンドを返却するなど迅速に対応する必要があります。ユーザーの長時間の待ち時間を避けるために、ここでは Tornado ベースの Apscheduler ライブラリを使用してシャーディング タスクをスケジュールします。