我对异步上传blob的问题感到困惑,希望在这里找到答案。
请先查看我的代码段,
public void UploadMultipleBlobs(List<string> filelocations, string containerName, AsyncCallback callback = null, string path = null)
{
try
{
Parallel.ForEach(filelocations, fileLocation =>
{
//File to Stream
MemoryStream str = new MemoryStream();
byte[] file = File.ReadAllBytes(fileLocation);
str.Write(file, 0, file.Length);
str.Seek(0, SeekOrigin.Begin);
//Operations
if (callback == null)
callback = new AsyncCallback(OnUploadCompleted);
BlobRequestOptions blobRequestOptions = new BlobRequestOptions();
blobRequestOptions.Timeout = new TimeSpan(1, 0, 0);
blobRequestOptions.RetryPolicy = retry;
CloudBlob currentBlob = container.GetBlobReference(blobName);
var result = currentBlob.BeginUploadFromStream(str, blobRequestOptions, callback, new Object[] { currentBlob, str });
currentBlob.EndUploadFromStream(result);
});
}
catch
{
throw;
}
}
private void OnUploadCompleted(IAsyncResult result)
{
try
{
// Get array passed to callback
Object[] states = (Object[])result.AsyncState;
var blob = (CloudBlob)states[0];
var stream = (MemoryStream)states[1];
// End the operation
//blob.EndUploadFromStream(result);
// Close the stream
stream.Close();
}
catch
{
throw;
}
}
我需要将mutil文件上传到Azure blob,文件数量可能是10-50,000,每个文件大约是10KB-50KB。目前代码片段对我来说很好。但是,如果我在回调中调用EndUploadFromStream,它在上传超过2,000个文件时总是抛出异常。我的意思是如果我在upload方法中删除EndUploadFromStream并在回调(OnUploadCompleted方法)中调用EndUploadFromStream,则会发生异常。如下的异常消息:
无法从传输连接读取数据:连接已关闭.StackTrace:at Microsoft.WindowsAzure.StorageClient.Tasks.Task`1.get_Result()
at Microsoft.WindowsAzure.StorageClient.CloudBlob.EndUploadFromStream(IAsyncResult asyncResult)
我不知道为什么会这样......希望得到你们的回答。
感谢。
答案 0 :(得分:0)
开始/结束代码看起来没问题。我注意到你没有做任何事情等待异步操作完成,所以问题可能与此有关。例如,如果您从控制台应用程序运行此应用程序,则应用程序可能会在所有上载完成之前退出,然后向您提供这些错误。如果EndUploadFromStream()
调用位于Parallel.ForEach()
内,则不会出现问题,因为它会导致Parallel.ForEach()
调用阻塞,直到所有上传完成为止。
因此,尝试添加代码以等待所有上传完成,看看是否可以修复它。一种简单的方法是将计数器初始化为上载总数,然后在回调内递减(使用Interlocked.Decremement()
进行线程安全)。另一个选项是使用Task.FromAsync()
来获取Task对象数组,然后使用Task.WaitAll()
等待它们完成。
另外,同时使用Parallel.ForEach()
和Begin / End方法通常是多余的 - Begin / End已经是异步的,因此使用多个线程调用它通常没有意义。由于你有这么大的项目清单,可能在这种情况下会有所不同,但可能并不多。除非您实际测量到显着差异,否则您最好使用简单的foreach
循环代替Parallel.ForEach()
。