2011-02-02 34 views
9

Tôi đang làm việc trên một chương trình truy cập ngẫu nhiên đọc/ghi nặng trên tệp lớn (cho đến 64 GB). Các tệp được cấu trúc cụ thể và để truy cập chúng, tôi đã tạo một khung công tác; sau một thời gian tôi đã cố gắng để kiểm tra hiệu suất trên nó và tôi đã nhận thấy rằng trên preallocated tập tin tuần tự viết hoạt động quá chậm để có thể chấp nhận được. Sau nhiều lần kiểm tra, tôi đã sao chép hành vi mà không có khung công tác của tôi (chỉ các phương thức FileStream); đây là phần mã (với phần cứng của tôi) sao chép vấn đề:Hành vi lạ với FileStream.WriteFile

FileStream fs = new FileStream("test1.vhd", FileMode.Open); 
byte[] buffer = new byte[256 * 1024]; 
Random rand = new Random(); 
rand.NextBytes(buffer); 
DateTime start, end; 
double ellapsed = 0.0; 
long startPos, endPos; 

BinaryReader br = new BinaryReader(fs); 
br.ReadUInt32(); 
br.ReadUInt32(); 
for (int i = 0; i < 65536; i++) 
    br.ReadUInt16(); 

br = null; 

startPos = 0; // 0 
endPos = 4294967296; // 4GB 
for (long index = startPos; index < endPos; index += buffer.Length) 
{ 
    start = DateTime.Now; 
    fs.Write(buffer, 0, buffer.Length); 
    end = DateTime.Now; 
    ellapsed += (end - start).TotalMilliseconds; 
} 

Thật không may vấn đề này dường như không thể đoán trước được, vì vậy đôi khi nó "hoạt động", đôi khi không. Tuy nhiên, sử dụng Process Monitor Tôi đã bắt gặp những sự kiện sau đây:

 
Operation Result Detail 
WriteFile SUCCESS Offset: 1.905.655.816, Length: 262.144 
WriteFile SUCCESS Offset: 1.905.917.960, Length: 262.144 
WriteFile SUCCESS Offset: 1.906.180.104, Length: 262.144 
WriteFile SUCCESS Offset: 1.906.442.248, Length: 262.144 
WriteFile SUCCESS Offset: 1.906.704.392, Length: 262.144 
WriteFile SUCCESS Offset: 1.906.966.536, Length: 262.144 
ReadFile SUCCESS Offset: 1.907.228.672, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal 
WriteFile SUCCESS Offset: 1.907.228.680, Length: 262.144 
ReadFile SUCCESS Offset: 1.907.355.648, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal 
ReadFile SUCCESS Offset: 1.907.490.816, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal 
WriteFile SUCCESS Offset: 1.907.490.824, Length: 262.144 
ReadFile SUCCESS Offset: 1.907.617.792, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal 
ReadFile SUCCESS Offset: 1.907.752.960, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal 
WriteFile SUCCESS Offset: 1.907.752.968, Length: 262.144 

Đó là, sau hơn-viết gần 2 GB, FileStream.Write bắt đầu gọi ReadFile sau mỗi WriteFile, và vấn đề này tiếp tục cho đến khi kết thúc quá trình; Ngoài ra, bù đắp mà tại đó vấn đề bắt đầu có vẻ là ngẫu nhiên. Tôi đã gỡ rối từng bước trong phương thức FileStream.Write và tôi đã xác minh rằng thực tế là WriteFile (Win32 API) mà, trong nội bộ, gọi ReadFile.

Lưu ý cuối cùng; Tôi không nghĩ rằng đó là một vấn đề phân mảnh tập tin: Tôi đã chống phân mảnh các tập tin cá nhân với contig!

+1

Cân nhắc nhớ chuyển [file ánh xạ] (http://msdn.microsoft.com/en-us/library/dd997372.aspx). – gor

+0

Bạn có nghĩa là tôi nên tạo tài liệu tham khảo từ Win32 API hoặc sử dụng .NET4? Trong trường hợp đầu tiên, sẽ tốt hơn nếu bạn tạo toàn bộ khung trong C/C++ (và tôi thực sự xem xét khả năng này!); sau này tôi cũng nên nâng cấp lên VS2010 hoặc sử dụng SharpDevelop: Tôi thích sử dụng những gì tôi có! – Atropo

+0

Nó có thể là một vấn đề đệm hệ điều hành, tôi không thể nhân rộng các lần đọc trên Win7 x64 và .Net 4.0. (Ngoài ra, hãy sử dụng các khối 'using', tôi không muốn khóc hôm nay) – user7116

Trả lời

1

Tôi tin rằng điều này phải làm với FileStream.Write/Read và giới hạn 2GB. Bạn đang chạy điều này trong một quá trình 32 bit? Tôi không thể tìm thấy bất kỳ tài liệu cụ thể về điều này, nhưng đây là một câu hỏi MSDN forum mà âm thanh giống nhau. Bạn có thể thử chạy điều này trong một quá trình 64bit.

Tôi đồng ý rằng việc sử dụng tệp ánh xạ bộ nhớ có thể là cách tiếp cận tốt hơn.

+0

Tôi đang sử dụng hệ thống Win7 64 bit! Tuy nhiên tôi không nghĩ rằng đó là một vấn đề của FileStream.Write: Tôi đã sửa lỗi nó (sau khi giải mã mscorlib)! – Atropo

+0

Điều đó rất có thể. Đó là sự hiểu biết của tôi rằng .NET vẫn được giới hạn trong các quy trình 32 bit hoặc giới hạn bộ nhớ 2 GB. Nhưng bạn không phân bổ nhiều hơn 2GB nên tôi nghi ngờ đó là vấn đề. –

+0

có nhắm mục tiêu ứng dụng .net "Bất kỳ CPU" hoặc x86 nào không? –

1

Tôi tìm thấy điều này từ MSDN. Nó có thể liên quan? Âm thanh với tôi mỗi tệp có một con trỏ được chia sẻ trên toàn cầu.

Khi đối tượng FileStream không có độc quyền trên tay cầm, một chuỗi khác có thể truy cập đồng thời tệp và thay đổi vị trí của con trỏ tệp của hệ điều hành được liên kết với bộ xử lý tệp. Trong trường hợp này, vị trí được lưu trong bộ nhớ cache trong đối tượng FileStream và dữ liệu được lưu trong bộ nhớ đệm trong bộ đệm có thể bị xâm nhập. Đối tượng FileStream thường xuyên thực hiện kiểm tra các phương thức truy cập bộ nhớ đệm được lưu trữ để đảm bảo rằng vị trí xử lý của hệ điều hành giống như vị trí được lưu trữ được sử dụng bởi đối tượng FileStream.

http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx

+0

Theo tài liệu, có vẻ là đủ để sử dụng 'FileOptions.WriteThrough' để vô hiệu hóa mọi bộ đệm giữa' FileStream.Write' và đĩa; nhưng tôi vẫn quan sát sự hiện diện của 'ReadFile' trong các bài kiểm tra. – Atropo