2010-01-26 6 views
5

Tôi muốn đặt ra một câu hỏi dường như đơn giản mà tôi không thể tìm thấy câu trả lời ở đâu cả. Có FAST thuật toán hiện đại cho đầu vào và/hoặc đầu ra tệp có thể được biên dịch với tất cả các trình biên dịch C++ tuân thủ chuẩn và hoạt động cho tất cả các hệ điều hành không yêu cầu thư viện bên ngoài không?Thuật toán nền tảng chéo nhanh để đọc/ghi tệp trong C++

  1. tôi đã phát hiện ra rằng cách nhanh nhất là sử dụng tập tin bộ nhớ ánh xạ, nhưng điều đó sẽ không làm vì chúng ta muốn cùng một mảnh mã làm việc trên tất cả các nền tảng
  2. chúng ta không thể sử dụng apis như Win32 API gây ra điều đó sẽ làm cho nền tảng cụ thể là
  3. tôi không muốn sử dụng c, tôi muốn thuật toán chỉ là mã C++ thuần túy với stl nếu khả thi, chứ không phải một số c xấu xí với tính năng asm hack/trick
  4. khung hoặc bên ngoài thư viện không thuộc về standart C++ không nên được sử dụng như wxWidgets, Qt, MFC, v.v.
  5. empasis của toàn bộ câu hỏi này là thuật toán là như NHANH càng tốt, một cái gì đó dọc theo dòng của tốc độ làm việc đó với các tập tin bộ nhớ ánh xạ, thậm chí nhanh hơn sẽ là tuyệt vời nhưng tôi biết đó là không thể

Bạn đã bao giờ thấy điều gì đó điên rồ được nghiên cứu bởi bất kỳ ai khác ngoại trừ tôi? Có phải một thuật toán như vậy thậm chí có thể?

Thanks cho bất kỳ khuyến nghị

Trả lời

9

Với các hạn chế sau:

thể được biên dịch với tất cả các trình biên dịch phù hợp tiêu chuẩn C++ và làm việc cho tất cả các hệ điều hành mà không có sự yêu cầu của thư viện bên ngoài?

Bạn đã tự giới hạn bản thân đối với các hàm IO của tệp thư viện chuẩn. Có lẽ chức năng POSIX (tùy thuộc vào tập hợp con của "tất cả các trình biên dịch C++ chuẩn tương ứng" mà bạn đang xem xét).

Nếu chúng không đủ nhanh cho bạn, bạn sẽ phải bắt đầu giảm một số hạn chế.

+1

Đồng ý. Chỉ tiêu chuẩn I/O tập tin C++ là từ thư viện chuẩn, nghĩa là. tệp tiêu đề '' hoặc ' '. Nếu bạn muốn tập tin nhanh I/O, điều quan trọng nhất là để ** không ** đọc/ghi các tập tin một byte tại một thời điểm, nhưng đọc/viết khối lớn trong một đi. – stakx

+0

toàn bộ tệp có thể đọc tất cả cùng một lúc với iostream không? điều đó có mang lại lợi thế về hiệu suất, mà tôi không nghĩ vậy? không phải là cstdio một c tiêu đề? – user258883

+2

Đọc toàn bộ tập tin cùng một lúc vẫn còn chậm hơn so với ánh xạ nó vào bộ nhớ. –

9

Điều này không liên quan gì đến thuật toán ".

Khi nói đến ghi dữ liệu vào tệp, bạn đang ở lòng thương xót của hệ điều hành - tệp ánh xạ bộ nhớ "nhanh" vì bạn chỉ ghi vào bộ nhớ và hệ điều hành đồng bộ hóa lại thời gian riêng của nó. Nếu hệ điều hành không hỗ trợ nó, bạn sẽ không may mắn về vấn đề đó - trừ khi bạn muốn thực hiện lớp lập bản đồ bộ nhớ của riêng mình.

Ngẫu nhiên, POSIX có mmap, vì vậy nếu bạn đang giới hạn mình vào hệ thống tuân thủ POSIX, bạn vẫn ổn.

2

Một số điểm:

  • này không có gì để làm với các thuật toán.
  • Muốn nhắm mục tiêu TẤT CẢ hệ điều hành không phải là mục tiêu hiệu quả (và không thể
  • mã của bạn không hoạt động trên nền tảng cụ thể cho đến khi bạn thử nghiệm nó). Thay vào đó, tôi tập trung vào một số hệ điều hành khả thi - nói POSIX + Win32.
  • Trong trường hợp đó, bạn có thể thực hiện ánh xạ bộ nhớ, ví dụ bằng cách triển khai mmap() cho Windows (trên cùng của MapViewOfFile() v.v. - mã nguồn git có triển khai mmap cho Windows nếu bạn cần cảm hứng)
  • Nếu bạn không thể sử dụng ánh xạ bộ nhớ, tôi khuyên bạn nên sử dụng api tệp C bình thường thay vì luồng tệp của C++ nếu hiệu suất là một vấn đề lớn. Mặc dù các luồng của C++ có tiềm năng hoạt động cao hơn đối với một số hoạt động, nhưng thực tế nó hơi chậm hơn một chút.
  • Tuy nhiên, để có được hiệu suất tốt, nó thường có thể là "đủ tốt" chỉ để đảm bảo bạn đang xử lý dữ liệu của mình theo cách thông minh. Đọc dữ liệu tuần tự, không đọc lại, vv Hoàn hảo là kẻ thù tốt;)
+0

@kusma: Tôi muốn được xem sự so sánh hiệu suất giữa các chức năng 'iostream' của' stdio' và C++. Bạn có thể nhờ bất kỳ cơ hội nào cho tôi đến các nguồn tài nguyên như vậy không? vì tôi đã từng xem xét mã nguồn thư viện C++ 'iostream' (cụ thể hơn, việc triển khai thực hiện với MinGW) và có ấn tượng rằng nó thực sự chỉ là một wrapper rất mỏng (dựa trên mẫu) xung quanh tệp C/I O chức năng. Vì vậy, tôi sẽ không mong đợi để thấy bất kỳ sự khác biệt đáng kể trong hiệu suất. – stakx

+0

Kẻ thù của thần? Yikes ... :) –

+0

stakx: Thật không may, không. Kết quả bị mất lâu. Tôi đã làm một số profiling trên MSVC trở lại khoảng năm 2001, sau khi một người bạn báo cáo chậm xuống đáng kể trên GCC/Linux từ sử dụng std :: istream (so với C API). IIRC, cả hai chúng tôi thấy rằng hiệu suất giảm là khoảng chừng 30%. Nó có thể là bộ nhớ phục vụ cho tôi sai về những con số, mặc dù. Drew: Xin lỗi, tôi có nghĩa là "kẻ thù của satan", tất nhiên;) – kusma

0

Các áp phích khác là chính xác trong hiệu suất đó luôn luôn là mâu thuẫn với tính tổng quát (đa nền tảng).

Tuy nhiên, nói chung, bạn sẽ nhận được kết quả tốt nhất bằng cách "đệm" đầu vào của bạn - sử dụng fread() để đọc các khối dữ liệu tương đối lớn và xử lý các dữ liệu đó.

Tôi biết đó là một câu trả lời khá cơ bản và chung chung, nhưng đó là về cụ thể như bạn có thể nhận được mà không cần nền tảng cụ thể hơn hoặc biết nhiều hơn về đầu vào cụ thể mà bạn đang xử lý.

1

Đọc tuần tự trong các khối là bội số (hoặc lũy thừa của 2) kích thước khối hệ thống tệp có thể hữu ích. Sau đó, tách rời dữ liệu của bạn sau khi chặn trong bộ nhớ. Có một tờ giấy trắng ở đâu đó, nơi họ đã thử nghiệm hiệu suất cho các kích thước khối khác nhau. Tôi ước tôi có thể tìm thấy nó một lần nữa.

Bạn cũng có thể thử có một chuỗi chuyên dụng để đọc khối từ tệp và một chuỗi khác thao tác dữ liệu trong bộ nhớ (với đồng bộ hóa thích hợp, tất nhiên). Điều này cho phép bạn sử dụng CPU để xử lý dữ liệu trong khi bạn đang chặn tệp của mình đọc cuộc gọi.

Dù sao, nếu bạn đưa ra những ý tưởng này, hãy cho chúng tôi biết nếu bạn nhận thấy sự khác biệt. Kết quả thực tế từ các bài kiểm tra điểm chuẩn của bạn sẽ rất thú vị.

+0

Hầu hết các ổ cứng đều sử dụng kích thước khối là bội số của 512 byte. Với các ổ đĩa cứng lớn hơn, nó có thể là 1024 hoặc lớn hơn. –

+0

Kích thước bộ đệm được sử dụng bởi các lớp trên/dưới có thể khác với kích thước của hệ thống tập tin. Thử nghiệm với các quyền hạn khác nhau của 2 (không giới hạn bản thân ở mức 512/1024, hãy đi tới 256KB). Tôi nhớ 4kiB là một số ma thuật được sử dụng trong một trong những lớp trong Linux, nhưng tôi không nhớ ở đâu. Xin lỗi tôi không thể cụ thể hơn. –

+0

4k là kích thước mặc định của khối hệ thống tệp. –

1

nhanh IO thường nắm để hai điều:

  1. Giảm thiểu dữ liệu sao chép
  2. Minimize bối cảnh kernel/user chuyển

Hầu hết tất cả các kỹ thuật IO cố gắng để giải quyết một hay khác. Mã đa nền tảng nhanh nhất cho IO mà tôi biết là hệ thống Perl IO. Tôi khuyên bạn nên xem the source. Tin tặc Perl đã dành hàng thập kỷ để có được IO càng nhanh càng tốt trên càng nhiều nền tảng càng tốt.

4

Để đặt một quan điểm khác về "lòng thương xót của hệ điều hành", hầu hết phí trên sao chép tệp nằm trong hệ điều hành. Tệp bị phân mảnh sẽ mất nhiều thời gian để đọc hơn tệp chống phân mảnh. Không có hàm C++ chung hoặc chuẩn để phát hiện các tệp bị phân mảnh.

Phương pháp nhanh nhất trong C++:

std::ifstream in_file; 
std::ofstream out_file; 

out_file << in_file.rdbuf(); 

Bạn có thể tìm thêm chi tiết bằng cách tìm kiếm trên web với các từ khóa "sao chép tập tin rdbuf". Các mảnh trên lá sao chép lên đến hệ điều hành, nhưng là di động trên tất cả các nền tảng. Bằng cách đọc vào các luồng C++ i/o, bạn có thể thiết lập kích thước của bộ đệm đọc, hoặc có nó sử dụng bộ đệm của riêng bạn.

Sao chép tệp nhanh hơn yêu cầu chức năng nền tảng cụ thể, chẳng hạn như chuyển DMA. Sử dụng các chủ đề và nhiều bộ đệm, có thể tăng tốc độ này; nhưng C++ không có hỗ trợ cho các chủ đề (có một tiêu chuẩn defacto, POSIX, mà không hỗ trợ chủ đề). Một luồng sẽ đọc vào bộ đệm trong khi một luồng khác ghi từ bộ đệm.