我为 BlockBlobClient 做了一个扩展方法,通过块 ID 获取特定块,我想知道是否可以调整此代码片段以提高性能/其他东西
public static async Task<T> GetBlockByIdAsync<T>(this BlockBlobClient blockBlobClient, string blockId, CancellationToken cancellationToken)
{
var blockListResponse = await blockBlobClient.GetBlockListAsync(cancellationToken: cancellationToken);
var blockList = blockListResponse.Value.CommittedBlocks.ToList();
var currentBlock = blockList.FirstOrDefault(a => a.Name == blockId);
if (currentBlock.Name == null)
{
throw new InvalidOperationException($"Could not find BlockId {blockId}");
}
var length = currentBlock.SizeLong;
var index = blockList.FindIndex(a => a.Name == blockId);
var offset = 0L;
for (var i = 0; i < index; i++)
{
offset += blockList[i].SizeLong;
}
var options = new BlobDownloadOptions()
{
Range = new HttpRange(offset, length)
};
var blockInfo = await blockBlobClient.DownloadStreamingAsync(options, cancellationToken);
return JsonSerializer.Deserialize<T>(blockInfo.Value.Content);
}
唯一真正突出的是
blockList
的多次迭代(3次)。
blockList.FirstOrDefault(a => a.Name == blockId)
blockList.FindIndex(a => a.Name == blockId)
for (var i = 0; i < index; i++)
您可以通过单次迭代来完成此操作,就像这样。
public static async Task<T> GetBlockByIdAsync<T>(this BlockBlobClient blockBlobClient, string blockId, CancellationToken cancellationToken)
{
var blockListResponse = await blockBlobClient.GetBlockListAsync(cancellationToken: cancellationToken);
var blockList = blockListResponse.Value.CommittedBlocks.ToList();
var length = 0L
var offset = 0L;
// iterate over all blocks until we find the block we want.
foreach (var block in blockList){
if (block.Name == blockId){
length = block.SizeLong;
break;
}
// We haven't found the block we want yet so update the offset.
offset += block.SizeLong;
}
// Check if we found the block we were looking for.
if (length == 0)
{
throw new InvalidOperationException($"Could not find BlockId {blockId}");
}
var options = new BlobDownloadOptions()
{
Range = new HttpRange(offset, length)
};
var blockInfo = await blockBlobClient.DownloadStreamingAsync(options, cancellationToken);
return JsonSerializer.Deserialize<T>(blockInfo.Value.Content);
}
注意我没有在本地运行这段代码,甚至没有尝试编译它,所以可能会有错误,但这个想法是合理的。
更新我错过了一个迭代:
blockListResponse.Value.CommittedBlocks.ToList();
当然,调用 list 可以防止对
CommittedBlocks
的任何重复调用,但这可能会更有效率。
假设
blockListResponse.Value.CommittedBlocks
返回 IEnumerable` 你甚至可以删除这个...
public static async Task<T> GetBlockByIdAsync<T>(this BlockBlobClient blockBlobClient, string blockId, CancellationToken cancellationToken)
{
var blockListResponse = await blockBlobClient.GetBlockListAsync(cancellationToken: cancellationToken);
var blockList = blockListResponse.Value.CommittedBlocks;
var length = 0L
var offset = 0L;
// iterate over all blocks until we find the block we want.
var blockListEnumerator = blockList.GetEnumerator();
while (blockListEnumerator.MoveNext())
{
var block = blockListEnumerator.Current as <Insert type of block here>;
if (block.Name == blockId){
length = block.SizeLong;
break;
}
// We haven't found the block we want yet so update the offset.
offset += block.SizeLong;
}
// Check if we found the block we were looking for.
if (length == 0)
{
throw new InvalidOperationException($"Could not find BlockId {blockId}");
}
var options = new BlobDownloadOptions()
{
Range = new HttpRange(offset, length)
};
var blockInfo = await blockBlobClient.DownloadStreamingAsync(options, cancellationToken);
return JsonSerializer.Deserialize<T>(blockInfo.Value.Content);
}