C# 对azure DownloadToStreamAsync接收的并行任务设置限制
我有一大堆文件(大约10k)需要从WindowsAzure存储下载。为了让它们并行下载,而不是一次下载一个,我使用blob DownloadToStreamAsync方法,该方法返回一个任务对象。然后,我使用将流保存到文件的方法设置任务ContinueWith 代码如下:C# 对azure DownloadToStreamAsync接收的并行任务设置限制,c#,azure,task-parallel-library,C#,Azure,Task Parallel Library,我有一大堆文件(大约10k)需要从WindowsAzure存储下载。为了让它们并行下载,而不是一次下载一个,我使用blob DownloadToStreamAsync方法,该方法返回一个任务对象。然后,我使用将流保存到文件的方法设置任务ContinueWith 代码如下: foreach (var File in ServerFiles) { string sFileName = File.Uri.LocalPath.ToString(); CloudBlockBlob oBlo
foreach (var File in ServerFiles)
{
string sFileName = File.Uri.LocalPath.ToString();
CloudBlockBlob oBlob = BiActionscontainer.GetBlockBlobReference(sFileName.Replace("/" + Container + "/", ""));
MemoryStream ms = new MemoryStream();
BlobRequestOptions f = new BlobRequestOptions();
Task downloadTask = oBlob.DownloadToStreamAsync(ms);
downloadTask.ContinueWith((Task task) =>
{
ms.Position = 0;
lock(lockObject)
{
using (FileStream file = new FileStream(ResultPath, FileMode.Append, FileAccess.Write))
{
byte[] bytes = ms.ToArray();
file.Write(bytes, 0, bytes.Length);
}
}
ms.Dispose();
});
}
此代码是在我们的一台服务器(而不是azure)上运行的工具的一部分-windows 2003 server。问题是,在该服务器上,我得到“操作已超时。windows 2003 standard上的Microsoft.WindowsAzure.Storage”,因此我认为可能是许多文件同时发出请求并阻塞了带宽
所以我想知道,在从第三方库获取任务对象的情况下,如何限制一次运行的并行程序的数量?并且仍然对即将到来的其余任务进行排队?您可以使用
信号量lim
进行此操作。设置您想要的并发请求数,然后在启动每个请求之前使用wait WaitAsync()
,在每个请求完成之后使用Release()
,最后等待剩余的任务
封装在helper方法中,它可能如下所示:
public static async Task ForEachAsync<T>(
this IEnumerable<T> items, Func<T, Task> action, int maxDegreeOfParallelism)
{
var semaphore = new SemaphoreSlim(maxDegreeOfParallelism);
var tasks = new List<Task>();
foreach (var item in items)
{
await semaphore.WaitAsync();
Func<T, Task> loopAction = async x =>
{
await action(x);
semaphore.Release();
};
tasks.Add(loopAction(item));
}
await Task.WhenAll(tasks);
}
另一种实现将使用来自TPL数据流的ActionBlock
。它知道如何在这里完成所有需要的操作,您只需设置它:
public static Task ForEachAsync<T>(
this IEnumerable<T> items, Func<T, Task> action, int maxDegreeOfParallelism)
{
var block = new ActionBlock<T>(
action,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism
});
foreach (var item in items)
{
block.Post(item);
}
block.Complete();
return block.Completion;
}
公共静态任务ForEachAsync(
此IEnumerable items,Func action,int maxDegreeOfParallelism)
{
var block=新动作块(
行动,
新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=MaxDegreeOfParallelism
});
foreach(项目中的var项目)
{
块.柱(项);
}
block.Complete();
返回块。完成;
}
如果我没有弄错的话,您的系统正在被冲洗,因为下面一行代码foreach(ServerFiles中的var文件)
。你需要在这里节流。
public static Task ForEachAsync<T>(
this IEnumerable<T> items, Func<T, Task> action, int maxDegreeOfParallelism)
{
var block = new ActionBlock<T>(
action,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism
});
foreach (var item in items)
{
block.Post(item);
}
block.Complete();
return block.Completion;
}