2010-07-29 33 views
9

Điều gì có thể được thực hiện để tăng tốc gọi các phương thức gốc từ mã được quản lý?Tối ưu hóa được quản lý cho các cuộc gọi gốc

Tôi đang viết một chương trình cần có khả năng quản lý danh sách các đối tượng có kích thước tùy ý và truy xuất thông tin từ các đối tượng đó ở tốc độ cao, nguồn cấp dữ liệu vào tập lệnh. Kịch bản là các bit của mã C# được biên dịch. Tôi đang viết một lớp giao diện cơ bản từ C++ (native) DLL/SO/etc cho lớp quản lý C# (.Net hoặc Mono).

Bây giờ, tôi đã thực hiện một số thử nghiệm và tôi nhận thấy rằng trung bình, PInvoking một phương pháp gốc từ mã được quản lý chậm hơn 100 lần so với thực hiện tất cả. nhanh chóng, để tham khảo).

Cú pháp tôi đã sử dụng là:

[DllImport("test.dll")] 
extern static public String test_method(String value); 

String returnedValue = test_method("hello world"); 

Có cách nào để cache một con trỏ đến chức năng, một số mã của Invoker nhanh, điều đó sẽ làm tăng tốc độ sau khi tải thư viện bản địa? Điều đó sẽ giải quyết vấn đề khá gọn gàng, vì vậy tôi nghi ngờ nó tồn tại. : P

Chỉnh sửa: Tôi không chỉ định, nhưng điều này cần phải hoạt động trên Windows, Linux (ít nhất là Ubuntu) và Mac OS X, tất cả cho cả x86 và x64. Nếu không tôi sẽ đi với một giao diện C + +/CLI và được thực hiện với nó, nhưng trừ khi đó làm việc cho tất cả 3 nền tảng, tôi không thể sử dụng nó.

+1

Có thể có một số chuyển đổi chuỗi ký tự và chuỗi ký tự diễn ra làm chậm tốc độ này xuống. Bạn có nhận được tỷ lệ hiệu suất tương tự không nếu bạn đo lường các hàm có nghĩa làint thay vì chuỗi? – x4u

+2

Tôi không có nghĩa là phải đề cập đến rõ ràng nhưng tôi sẽ kể từ 100x có vẻ ngoài dòng trong kinh nghiệm của tôi, nhưng bạn không chạy gỡ lỗi xây dựng \ và hoặc với trình gỡ lỗi đính kèm khi làm perf đo trên mã. Net? –

+0

@chibacity: Đó thực sự là một bản dựng gỡ lỗi với trình gỡ rối được đính kèm. Mặc dù tất cả các thành phần, bản địa và được quản lý, đều đã gỡ lỗi với các trình gỡ rối. Tôi sẽ chạy lại số của mình với bản phát hành bản phát hành và kiểm tra sự khác biệt. – ssube

Trả lời

3

Tiếp tục để bình luận câu hỏi của tôi, chúng tôi đã thiết lập rằng đó là một debug xây dựng với trình gỡ rối kèm theo. Điều này có tác động lớn đến về hiệu suất thời gian chạy của mã .Net. Lỗi dễ mắc phải. :)

Tôi đoán với bản phát hành bản phát hành và không có trình gỡ lỗi được đính kèm, sự khác biệt về hiệu suất giờ đây hợp lý hơn nhiều.

Nếu bạn có API rất trò chuyện và các phương thức gốc được gọi là giá rẻ thì chi phí cuộc gọi phương thức có thể là vấn đề về hiệu suất. Hãy thử và thiết kế một API ít trò chuyện hơn. Đây là một kỹ thuật điển hình được sử dụng để tăng hiệu suất của các giao tiếp của các hệ thống biên. Nếu hiệu suất có thể chấp nhận được sau khi phân loại vấn đề trình gỡ rối, có một kỹ thuật đơn giản mà tôi đã sử dụng để dễ dàng tăng hiệu suất đáng kể trong các API trò chuyện bằng cách chỉ thêm một thuộc tính duy nhất.

Trong các lớp mà bạn có các hàm đã nhập (tức là các hàm DllImport), hãy đặt thuộc tính SuppressUnmanagedCodeSecurity trên các lớp. Điều này sẽ loại bỏ một số kiểm tra bảo mật tốn kém từ mỗi cuộc gọi P/Gọi. Vui lòng xem tài liệu về số SuppressUnmanagedCodeSecurity để hiểu các chi tiết về việc này. Tôi có xu hướng giữ các hàm đã nhập của tôi được nhóm lại với nhau trong các lớp bên trong (chỉ chứa các hàm đã nhập) với thuộc tính này được áp dụng.

+0

Thật kỳ quặc, một bản phát hành (trên tất cả các bên) không có trình gỡ rối có cùng hiệu suất 1: 100. Tôi đã cố gắng để kiểm tra các chi phí interop, vì vậy tôi thiết kế một chức năng mà biên dịch xuống đến 4/5 asm hướng dẫn (một cmp, một jmp, hai mov và một ret). Để tạo một API ít trò chuyện hơn, có vẻ như đó là những gì tôi sẽ làm. Một cái gì đó giống như thay đổi trạng thái tối thiểu của trình điều khiển, đệm một số thông tin, có thể ghi vào bộ đệm dùng chung trong bộ nhớ không được quản lý và thỉnh thoảng gọi chức năng đồng bộ. Cảm ơn lời khuyên bảo mật. – ssube

3

Có lẽ chuỗi marshalling là những gì đang gây ra sự chậm lại. Để so sánh, hãy thử cấu hình một hàm lấy và trả về các kiểu C++ cơ bản như int.

Bạn cũng có thể thử thử nghiệm với C++/CLI. Bằng cách đó bạn có thể kiểm soát rõ ràng việc đầm lầy và có thể thấy sự cải thiện.

Trong ++/CLI lắp ráp C:

System::String^test_method(System::String^args) 
{ 
    pin_ptr<const wchar_t> pp = PtrToStringChars(args); 
    //This might leak, probably needs a smart pointer to wrap it 
    wchar_t* ret = native_method(pp); 
    return gcnew String^(ret); 
} 
+0

Tôi nên đã chỉ định, nhưng trừ khi điều đó sẽ làm việc cho Linux và Mac, thật không may là không có câu hỏi. Lựa chọn đầu tiên của tôi là giao diện C++/CLI, vì vậy câu trả lời của bạn là đúng như tôi đã nêu câu hỏi nhưng tôi quên việc chỉ định nền tảng chéo và không thấy bất kỳ cách nào để làm điều đó cho các hệ điều hành khác so với Windows. : \ – ssube

+0

Trình gỡ lỗi, chắc chắn sẽ loại trừ C++/CLI. –

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