2010-07-12 47 views
15

Tôi không hoàn toàn hiểu những gì làm cho phép nhân ma trận trong C# /. NET (và thậm chí Java) rất chậm.Tại sao nhân ma trận trong .NET lại chậm?

Hãy xem điểm chuẩn này ( source): Đang cố gắng tìm điểm chuẩn được cập nhật.

Java vs C# vs C++ breakdown http://img411.imageshack.us/img411/9324/perf.gif

C# 's nguyên và hiệu suất tăng gấp đôi là damn gần C++ biên dịch với MSVC++. 87% nhanh gấp đôi và 99% nhanh cho số nguyên 32 bit. Khá tốt, tôi muốn nói. Nhưng sau đó nhìn vào phép nhân ma trận. Khoảng cách mở rộng đến C# là khoảng 19% nhanh. Đây là một sự khác biệt khá lớn mà tôi không hiểu. Phép nhân ma trận chỉ là một loạt các phép toán đơn giản. Làm thế nào là nó nhận được như vậy chậm? Không nên nhanh như một số lượng tương đương của các hoạt động dấu chấm động hoặc số nguyên đơn giản?

Điều này đặc biệt quan tâm đến trò chơi và với XNA, ở đó hiệu suất ma trận và véc tơ rất quan trọng đối với những thứ như động cơ vật lý. Một thời gian trước, Mono đã thêm hỗ trợ cho các lệnh SIMD thông qua một số lớp vector và ma trận tiện lợi. Nó đóng khoảng trống và làm cho Mono nhanh hơn C++ viết tay, mặc dù không nhanh bằng C++ với SIMD. (source)

Matrix multiplication comparison http://img237.imageshack.us/img237/2788/resultse.png

gì đang xảy ra ở đây?

Chỉnh sửa: Nhìn kỹ hơn, tôi đã đọc nhầm biểu đồ thứ hai. C# xuất hiện khá gần. Điểm chuẩn đầu tiên có làm điều gì đó khủng khiếp sai? Rất tiếc, tôi đã bỏ lỡ số phiên bản trên điểm chuẩn đầu tiên. Tôi nắm lấy nó như là một tài liệu tham khảo hữu ích cho "đại số tuyến tính C# là chậm" mà tôi đã luôn luôn nghe. Tôi sẽ tìm cách khác.

+2

C# Version + Tùy chọn: .Net Framework 1.1.4322 Uh ... không có phiên bản mới hơn? – GalacticJello

+5

* ngồi và đợi xem JonSkeet phải nói gì về vấn đề * :-) – WestDiscGolf

+0

Bài kiểm tra được thực hiện với VS 2003. (Lưu ý phiên bản C++.) Do đó phiên bản cũ của .net. – cHao

Trả lời

13

Với các ma trận lớn như thế này, bộ nhớ cache CPU trở thành yếu tố hạn chế. Điều cực kỳ quan trọng là làm thế nào ma trận được lưu trữ. Và mã điểm chuẩn là so sánh táo và cam. Mã C++ sử dụng các mảng răng cưa, mã C# sử dụng các mảng hai chiều.

Viết lại mã C# để sử dụng các mảng có răng cưa cũng tăng gấp đôi tốc độ của nó. Viết lại ma trận nhân mã để tránh kiểm tra ranh giới chỉ mục mảng dường như vô nghĩa, không ai sẽ sử dụng mã như thế này cho các vấn đề thực sự.

+0

Cảm ơn, điều đó sẽ xóa mọi thứ. Vì vậy, tại sao tôi luôn luôn nghe (trong số các lý do khác) "XNA là chậm vì phép nhân trong ma trận C# là chậm"? Điều đó có đúng không? –

+1

Tôi không biết, đó là một tuyên bố không thể xác minh từ nơi tôi ngồi. Các lập trình viên XNA thường viết mã nhân ma trận riêng của họ? Mã C/C++ là kiên quyết khi nói đến tốc độ và bạn còn lại nhặt mảnh đạn ra khỏi tai khi nó nổ tung. Nếu có một vấn đề tốc độ với một thuật toán cụ thể trong C# thì bạn luôn có C/C++ để quay trở lại. –

+1

Không, họ sử dụng thư viện do XNA cung cấp. –

7

Rõ ràng tác giả điểm chuẩn không hiểu sự khác biệt giữa các mảng có răng cưa và đa chiều trong C#. Nó thực sự không phải là một quả táo để so sánh. Khi tôi thay đổi mã để sử dụng mảng răng cưa thay vì mảng đa chiều để nó hoạt động theo cách tương tự như Java thì mã C# kết thúc chạy nhanh gấp hai lần ... làm cho nó nhanh hơn Java (mặc dù chỉ vừa đủ và có lẽ không có ý nghĩa thống kê). Trong C# mảng đa chiều chậm hơn vì có thêm công việc liên quan đến việc tìm kiếm khe mảng và vì kiểm tra giới hạn mảng không thể được loại bỏ cho chúng ... được nêu ra.

Xem điều này question để có phân tích chi tiết hơn về lý do mảng đa chiều chậm hơn mảng bị lởm chởm.

Xem trang này blog để biết thêm thông tin về kiểm tra giới hạn mảng. Bài báo đặc biệt cảnh báo chống lại việc sử dụng các mảng đa chiều cho phép nhân ma trận.

3

Dưới đây là một tiêu chuẩn được cập nhật đối phó với ma trận multiplcation (và một số tiêu chuẩn sử dụng mới Thư viện Parallel Task):

Parallel Matrix Multiplication with the Task Parallel Library (TPL)

bài viết sẽ chuyển sang phương pháp khác nhau, và giải thích lý do tại sao các mảng đa chiều là một lựa chọn người nghèo:

cách dễ nhất để làm ma trận nhân là với một mảng .NET đa chiều với i, j, k đặt hàng trong vòng . Các vấn đề gấp hai lần. Thứ nhất, i, j.k đặt hàng truy cập bộ nhớ theo kiểu bận rộn khiến dữ liệu ở các vị trí khác nhau được được kéo vào. Thứ hai, nó đang sử dụng mảng đa chiều . Có, các mảng đa chiều .NET thuận tiện, nhưng rất chậm.

10

Để giải thích nguồn gốc của ý tưởng rằng XNA hoạt động ma trận là chậm:

Trước hết đó là Gotcha người mới bắt đầu cấp: XNA Matrix lớp của operator* sẽ thực hiện một số bản. Điều này chậm hơn những gì bạn có thể mong đợi từ mã C++ tương đương.

(Tất nhiên, nếu bạn sử dụng Matrix.Multiply(), sau đó bạn có thể vượt qua bằng cách tham khảo.)

Lý do thứ hai là .NET Compact Framework được sử dụng bởi XNA trên Xbox 360 không có quyền truy cập vào các phần cứng VMX (SIMD) có sẵn cho các trò chơi gốc, C++.

Đây là lý do tại sao bạn tiếp tục nghe rằng nó chậm, ít nhất. Như bạn có thể thấy từ các tiêu chuẩn bạn đã đăng - nó không thực sự là "chậm", khi bạn so sánh táo với táo.

+1

Điều đó có ý nghĩa. Có lẽ một số quan niệm sai lầm đến từ việc sử dụng toán tử. –

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