CloudBlockBlob.DownloadToStream与DownloadRangeToStream

时间:2017-01-23 15:59:31

标签: c# asp.net azure azure-storage-blobs azure-sdk-.net

尝试使用ASP.NET azure SDK从blob存储中下载图像。

我在另一篇文章中读到,DownloadToStream确实将blob破碎成小块并且并行下载它们以提高性能。我相信这就是DownloadRangeToStream的用途。

我无法找到任何关于DownloadToStream的文档或代码确认,并且持怀疑态度,因为它具有与直接从blob url下载的运行时相同(每次下载0.5-3s)。这是我的下载方法的代码,给出了相同的性能。

使用CloudBlockBlob.DownloadToStream:

private Bitmap DownloadFromBlob(String set) {

    CloudStorageAccount storageAccount = CloudStorageAccount.Parse( CloudConfigurationManager.GetSetting("StorageConnectionString"));

    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    CloudBlobContainer container = blobClient.GetContainerReference("templates");

    CloudBlockBlob blockBlob = container.GetBlockBlobReference(set + ".png");

    using (var memoryStream = new MemoryStream()) {
        blockBlob.DownloadToStream(memoryStream);

        return (memoryStream == null) ? null : (Bitmap)Image.FromStream(memoryStream);
    }
}

使用Image.FromStream:

private Bitmap DownloadImageFromUrl(string url) {
    try {
        using (WebClient client = new WebClient()) {
            byte[] data = client.DownloadData(url);
            using (MemoryStream mem = (data == null) ? null : new MemoryStream(data)) {
                return (data == null || mem == null) ? null : (Bitmap)Image.FromStream(mem);
            }
        }
    } catch (WebException e) {
        return null;
    }
}

我正在尝试增加范围为.5-12 MB的图像的下载时间。我试图为这些图像实现我自己的DownloadRangeToStream方法,其代码如下。我是否需要这样做或者DownloadToStream已经为我做了吗?此方法产生与上面的DownloadFromBlob方法相同的运行时..

使用downloadRangeToStream:

private Image getImageFromStream(string set)
    {
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
        CloudConfigurationManager.GetSetting("StorageConnectionString"));

        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

        CloudBlobContainer container = blobClient.GetContainerReference("templates");

        CloudBlockBlob blockBlob = container.GetBlockBlobReference(set + ".png");

        using (MemoryStream ms = new MemoryStream())
        {

            ParallelDownloadBlob(ms, blockBlob);
            return (ms == null) ? null : Image.FromStream(ms);
        }
    }
private static void ParallelDownloadBlob(Stream outPutStream, CloudBlockBlob blob)
    {
        blob.FetchAttributes();
        int bufferLength = 1 * 1024 * 1024;//1 MB chunk
        long blobRemainingLength = blob.Properties.Length;
        Queue<KeyValuePair<long, long>> queues = new Queue<KeyValuePair<long, long>>();
        long offset = 0;
        while (blobRemainingLength > 0)
        {
            long chunkLength = (long)Math.Min(bufferLength, blobRemainingLength);
            queues.Enqueue(new KeyValuePair<long, long>(offset, chunkLength));
            offset += chunkLength;
            blobRemainingLength -= chunkLength;
        }
        Parallel.ForEach(queues,
            new ParallelOptions()
            {
        //Gets or sets the maximum number of concurrent tasks
        MaxDegreeOfParallelism = 10
            }, (queue) =>
            {
                using (var ms = new MemoryStream())
                {
                    blob.DownloadRangeToStream(ms, queue.Key, queue.Value);
                    lock (outPutStream)
                    {
                        outPutStream.Position = queue.Key;
                        var bytes = ms.ToArray();
                        outPutStream.Write(bytes, 0, bytes.Length);
                    }
                }
            });
    }

1 个答案:

答案 0 :(得分:8)

根据我的理解,DownloadRangeToStreamprivate static void ParallelDownloadBlob(Stream outPutStream, CloudBlockBlob blob) { blob.FetchAttributes(); int bufferLength = 1 * 1024 * 1024;//1 MB chunk long blobRemainingLength = blob.Properties.Length; Queue<KeyValuePair<long, long>> queues = new Queue<KeyValuePair<long, long>>(); long offset = 0; while (blobRemainingLength > 0) { long chunkLength = (long)Math.Min(bufferLength, blobRemainingLength); queues.Enqueue(new KeyValuePair<long, long>(offset, chunkLength)); offset += chunkLength; blobRemainingLength -= chunkLength; } Parallel.ForEach(queues, new ParallelOptions() { //Gets or sets the maximum number of concurrent tasks MaxDegreeOfParallelism = 10 }, (queue) => { using (var ms = new MemoryStream()) { blob.DownloadRangeToStream(ms, queue.Key, queue.Value); lock (outPutStream) { outPutStream.Position = queue.Key; var bytes = ms.ToArray(); outPutStream.Write(bytes, 0, bytes.Length); } } }); } 只会发送下载流的请求,您可以利用Fiddler来捕获流量,如下所示:

使用retrieve_token时,您可以将blob分成更小的部分并自行并行下载以提高性能。这是我的代码片段,您可以参考它。

mydata$weekday <- ifelse(mydata$weekday %in% c_weekday, "c_weekday", "c_weekend")

<强>结果:

此外,还有一些关于上传/下载blob的博客,您可以参考它们(blog1blog2)。