2017-04-24 24 views
6

Tôi muốn tải các tài liệu XML lớn vào các đối tượng XDocument. Cách tiếp cận đồng bộ đơn giản sử dụng XDocument.Load(path, loadOptions) hoạt động tốt, nhưng chặn trong một thời gian dài không thoải mái trong ngữ cảnh GUI khi tải các tệp lớn (đặc biệt là từ bộ nhớ mạng).Tải XDocument không đồng bộ

Tôi đã viết phiên bản không đồng bộ này với mục đích cải thiện khả năng phản hồi trong tải tài liệu, đặc biệt khi tải tệp qua mạng.

public static async Task<XDocument> LoadAsync(String path, LoadOptions loadOptions = LoadOptions.PreserveWhitespace) 
    { 
     String xml; 

     using (var stream = File.OpenText(path)) 
     { 
      xml = await stream.ReadToEndAsync(); 
     } 

     return XDocument.Parse(xml, loadOptions); 
    } 

Tuy nhiên, trên 200 MB tệp thô XML được tải từ đĩa cục bộ, phiên bản đồng bộ hoàn tất sau vài giây. Phiên bản không đồng bộ (chạy trong một bối cảnh 32-bit) thay vì ném một OutOfMemoryException:

at System.Text.StringBuilder.ToString() 
    at System.IO.StreamReader.<ReadToEndAsyncInternal>d__62.MoveNext() 

Tôi tưởng tượng này là do sự biến chuỗi tạm thời sử dụng để giữ XML thô trong bộ nhớ cho phân tích bởi các XDocument. Có lẽ trong kịch bản đồng bộ, XDocument.Load() có thể truyền qua tệp nguồn và không bao giờ cần phải tạo một Chuỗi lớn duy nhất để giữ toàn bộ tệp.

Có cách nào để tận dụng tối đa cả hai thế giới không? Tải XDocument với I/O hoàn toàn không đồng bộ và không cần phải tạo một chuỗi tạm thời lớn?

+0

Có lẽ bạn nên sử dụng 'XDocument.Load (stream)'? – DavidG

+0

Làm cách nào để hoạt động tải không đồng bộ? – Hydrargyrum

+0

Vâng, trong chính nó sẽ không, nhưng nó sẽ loại bỏ biến chuỗi bạn có ở đây và hy vọng ngoại lệ OOM. – DavidG

Trả lời

2

Trước hết nhiệm vụ không được chạy không đồng bộ. Bạn sẽ cần phải sử dụng lệnh được xây dựng trong async IO hoặc tự xoay một nhiệm vụ trên nhóm luồng. Ví dụ:

public static async Task<XDocument> LoadAsync 
(String path 
, LoadOptions loadOptions = LoadOptions.PreserveWhitespace 
) 
{ 
    return Task.Run(()=>{ 
    using (var stream = File.OpenText(path)) 
     { 
      return XDocument.Load(stream, loadOptions); 
     } 
    }); 
} 

và nếu bạn sử dụng stream version của phân tích thì bạn không nhận được chuỗi tạm thời.

+3

Ok. Đây là những gì tôi đã nêu trong bình luận cuối cùng của tôi về câu hỏi. Vì vậy, điều này sẽ được sử dụng một thread thread-pool để lái xe I/O yêu cầu ngầm, như XDocument nhai theo cách của nó thông qua các dòng. Và I/O đó sẽ tự động ngăn chặn luồng công nhân của Task. Có vẻ như đây là cách tốt nhất có thể thực hiện được, trong trường hợp không có thực thi XDocument.LoadAsync() thực sự sử dụng các lệnh Async I/O thích hợp dưới mui xe. Tôi không thấy bất kỳ lợi thế nào để gọi rõ ràng File.OpenText.Cũng có thể gọi XDocument.Load (đường dẫn) – Hydrargyrum

+0

Nếu bạn đang đọc 10 trong số hàng nghìn XDocuments trên một máy chủ song song bạn có thể lo lắng về việc ăn cắp một luồng từ thread thread thay vì sử dụng đúng async IO nhưng đây thực sự là một mối quan tâm ? – bradgonesurfing

+1

Có lẽ là không. Do đó nhận xét của tôi rằng nó có thể đủ tốt. Tôi đã upvoted và chấp nhận anyway – Hydrargyrum

Các vấn đề liên quan