2013-08-13 49 views
8

Tôi đang cố gắng triển khai hoàn toàn không đồng bộ tải xuống blob với .NET 4.5 async & đang chờ.Tải xuống không đồng bộ một đốm màu Azure thành chuỗi có .NET 4.5 async, đang chờ

Giả sử toàn bộ đốm màu có thể vừa với bộ nhớ cùng một lúc và chúng tôi muốn giữ nó trong một số string.

Code:

public async Task<string> DownloadTextAsync(ICloudBlob blob) 
{ 
    using (Stream memoryStream = new MemoryStream()) 
    { 
     IAsyncResult asyncResult = blob.BeginDownloadToStream(memoryStream, null, null); 
     await Task.Factory.FromAsync(asyncResult, (r) => { blob.EndDownloadToStream(r); }); 
     memoryStream.Position = 0; 

     using (StreamReader streamReader = new StreamReader(memoryStream)) 
     { 
      // is this good enough? 
      return streamReader.ReadToEnd(); 

      // or do we need this? 
      return await streamReader.ReadToEndAsync(); 
     } 
    } 
} 

Cách sử dụng:

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageAccountConnectionString")); 
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); 
CloudBlobContainer container = blobClient.GetContainerReference("container1"); 
CloudBlockBlob blockBlob = container.GetBlockBlobReference("blob1.txt"); 

string text = await DownloadTextAsync(blockBlob); 

là mã này đúng và điều này thực sự là hoàn toàn không đồng bộ? Bạn sẽ thực hiện điều này một cách khác nhau?

Tôi đánh giá cao một số giải thích thêm:

  1. GetContainerReferenceGetBlockBlobReference không cần phải async vì họ không liên lạc với máy chủ nào, phải không?

  2. streamReader.ReadToEnd cần phải không đồng bộ hay không?

  3. Tôi là một chút nhầm lẫn về những gì BeginDownloadToStream không .. vào thời điểm EndDownloadToStream được gọi, không dòng ký ức của tôi có tất cả dữ liệu bên trong? hoặc là luồng chỉ mở trước đọc?

Cập nhật: (tính lưu trữ 2.1.0.0 RC)

Async hiện được hỗ trợ natively.

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageAccountConnectionString")); 
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); 
CloudBlobContainer container = blobClient.GetContainerReference("container1"); 
CloudBlockBlob blockBlob = container.GetBlockBlobReference("blob1.txt"); 

string text = await blockBlob.DownloadTextAsync(); 

Trả lời

12

Mã này có đúng và điều này thực sự hoàn toàn không đồng bộ không?

Có.

Bạn có thực hiện điều này một cách khác nhau không?

Có. Cụ thể, các trình bao bọc TaskFactory.FromAsync hiệu quả hơn nhiều nếu bạn chuyển vào cặp phương thức Begin/End thay vì truyền trong một IAsyncResult hiện có. Như thế này:

await Task.Factory.FromAsync(blob.BeginDownloadToStream, 
    blob.EndDownloadToStream, memoryStream, null); 

Tôi cũng thích quấn những thành phương pháp mở rộng riêng biệt vì vậy tôi có thể gọi nó như thế này:

await blog.DownloadToStreamAsync(memoryStream); 

Lưu ý rằng phiên bản tiếp theo của các thư viện client (2.1, hiện tại RC) sẽ có các phương thức có sẵn là async, ví dụ: DownloadToStreamAsync.

GetContainerReference và GetBlockBlobReference không cần phải không đồng bộ vì chúng chưa liên hệ với máy chủ, phải không?

Đúng.

Trình phát theo luồng.Đọc đầuBạn có cần đồng bộ hay không?

Nó không (và không nên). Stream là một trường hợp bất thường với chương trình async. Thông thường, nếu có phương thức async thì bạn nên sử dụng phương thức này trong mã async của mình, nhưng hướng dẫn đó không giữ cho các loại Stream. Lý do là lớp cơ sở Stream không biết liệu việc triển khai của nó có đồng bộ hay không đồng bộ, vì vậy nó giả định rằng nó đồng bộ và theo mặc định sẽ giả mạo các hoạt động không đồng bộ của nó bằng cách thực hiện công việc đồng bộ trên một chuỗi nền. Luồng không đồng bộ thực sự (ví dụ: NetworkStream) ghi đè luồng này và cung cấp các hoạt động không đồng bộ thực sự. Luồng đồng bộ (ví dụ: MemoryStream) giữ nguyên hành vi mặc định này.

Vì vậy, bạn không muốn gọi ReadToEndAsync trên MemoryStream.

Tôi hơi bối rối về những gì BeginDownloadToStream thực hiện .. vào thời điểm EndDownloadToStream được gọi, luồng bộ nhớ của tôi có tất cả dữ liệu bên trong không?

Có. Hoạt động là DownloadToStream; nó, nó tải một blob vào một dòng. Vì bạn đang tải một blob vào một MemoryStream, blob hoàn toàn nằm trong bộ nhớ vào thời điểm hoạt động này hoàn tất.

1
  1. Đúng, họ không cần phải async nếu họ sẽ không thể hoạt động lâu dài, mà họ không nên' được.

  2. Có thể không, mặc dù tôi không quen với việc triển khai cụ thể này. Tôi hy vọng rằng vì bạn đang chờ đợi luồng kết thúc trước thời điểm này nên không có mạng lưới hoạt động, và do đó không có hoạt động tốn kém, để thực hiện tại thời điểm này. Bạn chỉ nên kéo dữ liệu từ một bộ đệm, và nó sẽ được nhanh chóng. Điều này là dễ dàng, đủ để kiểm tra, tuy nhiên. Bạn có thể sử dụng một cái gì đó như Fiddler để xem có giao tiếp mạng nào đang diễn ra trong suốt cuộc gọi đó không, bạn có thể chỉ cần thời gian để xem liệu nó có đủ dài để xuất hiện mạng IO đang diễn ra không, hoặc bạn có thể xem qua các tài liệu này triển khai luồng cụ thể. Hoặc bạn chỉ có thể sử dụng phương pháp async để an toàn, mà tôi sẽ đề xuất, thay vì mạo hiểm bị nhầm lẫn. Tôi sẽ khá ngạc nhiên khi thấy rằng này cần để được đồng bộ hóa.

  3. Xem # 2.

+0

Các tài liệu không phải là quá dài dòng về vấn đề này .. Tôi đoán thử nghiệm là theo thứ tự, tôi sẽ mất một blob lớn và làm một số thời gian. Điều này là rất khó khăn và tôi mong đợi nó được rõ ràng :) – talkol

+0

Các tài liệu rõ ràng trên BeginDownloadToStream - gọi lại (trong trường hợp của bạn, mã gọi EndDownloadToStream) được gọi khi "hoạt động hoàn thành". –

+0

@PeterRitchie Tôi không chắc chắn 100% hoạt động chính xác là gì. Nó là toàn bộ tải xuống hay chỉ là khởi đầu (truy vấn đầu tiên của máy chủ). Nếu đó là trước đây, tôi có cách nào khác để nhận thông báo về tiến độ hoặc hủy nếu quá dài/lớn không? – talkol

0

Xem: http://channel9.msdn.com/Events/TechEd/NorthAmerica/2013/WAD-B406#fbid=lCN9J5QiTDF đối với một số hoạt động hữu ích tốt nhất bao gồm cả lý do tại sao bạn nên tránh sử dụng dòng Memory như mã gốc không :)

Một lưu ý là bạn có hai lựa chọn chính để tải về Blobs, Cloud [Khối | Trang ] Blob.Tải xuống [Phạm vi] Tới * các phương thức và luồng được cung cấp bởi OpenRead().Trong trường hợp tải xuống toàn bộ blob (hoặc phạm vi nếu được yêu cầu) được phát hành dưới dạng một cuộc gọi GET duy nhất và kết quả được truyền/ghi đến vị trí thích hợp, trong trường hợp xảy ra lỗi tạm thời, thì các byte chưa nhận được được yêu cầu theo chính sách thử lại.

Các phương pháp OpenRead dành cho khách hàng muốn xử lý dữ liệu trong một khoảng thời gian dài hơn và không giữ kết nối mở. Chúng hoạt động bằng cách chỉ định một độ dài nhất định sẽ được prebuffered ở phía máy khách, khi dòng chảy ra khỏi dữ liệu đệm trước, phạm vi phụ tiếp theo được yêu cầu.

Cuối cùng, tính đến 2.1 RTM một phương pháp DownloadTextAsync được cung cấp mà làm tất cả những điều này cho bạn :) (với quá tải tùy chọn để xác định mã hóa, mặc định là UTF8)