2009-07-05 34 views
5

Tôi có một chương trình nhỏ để đọc và ghi tệp trên đĩa. Chia nhỏ nó xuống mức đơn giản nhất, nó đọc byte từ một luồng tệp và ghi chúng vào luồng khác. Nó thực hiện nhiệm vụ của nó tốt, nhưng nó không phải là điều nhanh nhất.Cách nhanh nhất để đọc/ghi vào đĩa trong .NET là gì?

Tôi đã nhìn thấy các ứng dụng khác có thể xé qua một gigabyte hoặc nhiều lần đọc/ghi với tốc độ tuyệt vời. Rõ ràng là chúng hoạt động gần với kim loại hơn một chút ứng dụng .NET.

API .NET hiệu quả nhất để truyền trực tuyến đến/từ đĩa là gì? API win32 nào có sẵn (và giá trị p/gọi cho) để truy cập đĩa nhanh?

+3

Tôi không thấy lý do tại sao các cuộc gọi WinAPI phải nhanh hơn các lớp .NET - sau khi tất cả, sau này sử dụng nội bộ trước đó. Bên cạnh đó, một tập tin ánh xạ bộ nhớ (http://en.wikipedia.org/wiki/Memory_mapped_file) có phù hợp không? – Noldorin

+0

Tại sao Dot.net có nhiều cách để ghi vào một tập tin? Đọc và ghi các tập tin là khá cơ bản và nó không có ý nghĩa trong việc có một "nhanh" và "chậm" hình thức - như không ai sẽ sử dụng phiên bản "chậm" cho cả hai đều có cùng mục tiêu. –

+0

Trong vòng nửa giờ, tôi có thể thiết lập thử nghiệm so sánh các hoạt động của tệp .net (có thể là một phần của câu hỏi) và một ứng dụng gốc với IO chuyên sâu (như QuickPAR) sẽ thổi các cửa ra khỏi .NET. ứng dụng. Đó là điểm của câu hỏi - Làm thế nào để bạn đạt được thông lượng đĩa tối ưu trong .NET? – Will

Trả lời

10

Tệp nhanh I/O ít hơn về các cuộc gọi API cụ thể mà bạn thực hiện, mà là cách bạn kiến ​​trúc ứng dụng hoạt động với I/O.

Nếu bạn đang thực hiện tất cả các I/O hoạt động trên một chủ đề duy nhất một cách tuần tự, ví dụ

  1. đọc block vào bộ nhớ
  2. Process khối trong bộ nhớ bằng cách nào đó
  3. Viết khối ra nộp
  4. Lặp lại cho đến khi thực hiện ...

bạn đang bottlenecking I/O băng thông của hệ thống trong proces hát vòng lặp của một sợi đơn. Một thay thế, nhưng thiết kế phức tạp hơn là đa luồng ứng dụng của bạn để tối đa hóa thông lượng và tránh thời gian chờ đợi. Điều này cho phép hệ thống tận dụng đồng thời cả băng thông bộ điều khiển CPU và I/O. Một thiết kế điển hình cho điều này sẽ giống như thế:

  1. Một (hoặc hơn) đề người lao động đọc dữ liệu từ đĩa và thêm chúng vào một hàng đợi đầu vào chia sẻ
  2. Một (hoặc hơn) đề người lao động đọc blocks from the chia sẻ hàng đợi đầu vào, xử lý chúng và thêm chúng vào hàng đợi đầu ra được chia sẻ
  3. Một (hoặc nhiều) chuỗi công việc đọc được xử lý bị chặn từ hàng đợi đầu ra được chia sẻ và ghi chúng vào tệp đầu ra thích hợp.

Đây không phải là một kiến ​​trúc dễ dàng để thiết kế đúng và đòi hỏi một chút suy nghĩ để tránh tạo ra sự tranh cãi trong bộ nhớ, hoặc áp đảo hệ thống với yêu cầu I/O đồng thời. Bạn cũng cần phải cung cấp siêu dữ liệu kiểm soát để trạng thái xử lý đầu ra không được quản lý trên ngăn xếp cuộc gọi của một luồng mà là trong hàng đợi công việc đầu vào/đầu ra. Bạn cũng phải đảm bảo rằng bạn chuyển đổi và viết đầu ra theo đúng thứ tự, vì với I/O đa luồng, bạn không thể chắc chắn công việc được đặt trên hàng đợi đầu vào theo thứ tự được bảo đảm. Nó phức tạp - nhưng có thể, và nó có thể có sự khác biệt đáng kể về thông lượng qua một cách tiếp cận nối tiếp.

Nếu bạn thực sự có thời gian và muốn nén từng ounce hiệu suất từ ​​hệ thống, bạn cũng có thể sử dụng I/O completion ports - một API mức tương đối thấp - để tối đa hóa thông lượng.

Chúc may mắn.

1

Bạn đã lược tả ứng dụng của mình để xác định xem I/O đĩa có phải là nút cổ chai không?

Loại phần cứng nào bạn đang chạy tính năng này? Cấu hình phần cứng là gì?

Trong .NET, bạn có thể thử không gian tên System.IO.File.

Đối với các hàm Win32, bạn có thể thử chuỗi CreateFile, WriteFile, ReadFile.

Một ví dụ:

http://msdn.microsoft.com/en-us/library/bb540534(VS.85).aspx

này chắc chắn không phải cắt và sấy khô. Đó là tất cả về thử nghiệm và đo lường.

+0

Cá nhân tôi sẽ * rất * ngạc nhiên nếu đĩa IO là vấn đề ... Tôi chưa bao giờ gặp phải bất kỳ vấn đề nào tối đa đĩa IO với bất kỳ phần tử .NET nguyên thủy nào ... (trừ khi có lẽ anh ta đang chạy .NET 1 ở ​​đâu Tôi tin rằng các luồng tập tin không có bộ đệm tích hợp) – jerryjvl

+1

Câu hỏi không phải là về cách thức, nhưng làm thế nào NHANH. Cảm ơn bạn đã tip về System.IO.File (mỉa mai, ftw). – Will

0

BinaryReaderBinaryWriter với kích thước bộ đệm phù hợp khá nhanh. Nếu bạn đang đọc vào cấu trúc, cách tiếp cận không an toàn được mô tả in this article sẽ giúp bạn đọc nhanh và viết cũng tương tự. Tôi cũng đồng ý với đề xuất kiểm tra lại rằng I/O thực sự là nút cổ chai. Lần đầu tiên tôi bắt gặp bài viết đó do một sai lầm như vậy.

6

Hỗ trợ tệp .NET đủ nhanh (có thể so sánh với các hàm Win32 gốc). Một số tùy chọn có thể giúp bạn cải thiện hiệu suất của bạn:

  1. Nếu đọc của bạn/ghi là tuần tự, giúp người quản lý bộ nhớ đệm bằng cách áp dụng chiến lược phù hợp - cung cấp RandomAccess or SequentalScan, khi instantiating FileStream
  2. Xem xét sử dụng một bộ nhớ đệm lớn để lưu trữ Đọc dữ liệu
  3. Nếu bạn sao chép nhiều tệp nhỏ, trước tiên bạn có thể đọc nhiều tệp vào bộ nhớ đệm cùng một lúc (xem 2) và sau đó ghi tệp vào đĩa
  4. Nếu nguồn và luồng đích được đặt ở các vị trí khác nhau (nghĩa là, không phải trên cùng một ổ đĩa cứng, có thể một tệp trên mạng, một tệp khác trên ổ cứng cục bộ, v.v.), bạn có thể sử dụng mẫu không đồng bộ để tăng tốc, đọc dữ liệu bằng cách sử dụng BeginRead, sau đó ghi dữ liệu bằng cách sử dụng BeginWrite và trong khi dữ liệu đang được đọc đọc khối dữ liệu tiếp theo bằng cách sử dụng BeginRead.
  5. Nếu bạn vẫn cho rằng hiệu suất là không đủ (tuy nhiên từ thử nghiệm của tôi là tương đương hoặc thậm chí nhanh hơn bản sao Windows bên trong), bạn có thể sử dụng chức năng CopyFileEx Win32 (nhưng chức năng này hoạt động với tệp, chứ không phải luồng).
+1

Một phần của câu hỏi là sử dụng đúng cách, câu trả lời này ít nhất là cố gắng hoàn thành. Cảm ơn. – Will

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