2010-08-13 6 views
9

Lấy các chuỗi của một chuỗi là thao tác thao tác chuỗi rất phổ biến, nhưng tôi nghe nói rằng có thể có sự khác biệt đáng kể về hiệu suất/triển khai giữa nền tảng Java và .NET. Cụ thể, tôi nghe nói rằng trong Java, java.lang.String cung cấp hằng số hoạt động thời gian cho substring, nhưng trong .NET, System.String cung cấp tuyến tính hiệu suất Substring.So sánh hiệu suất hoạt động chuỗi con giữa .NET và Java

Đây có phải là trường hợp thực sự không? Điều này có thể được xác nhận trong tài liệu/mã nguồn, v.v. Việc triển khai này có cụ thể hay được chỉ định bởi ngôn ngữ và/hoặc nền tảng không? Những ưu và khuyết điểm của mỗi cách tiếp cận là gì? Những gì một người nên di chuyển từ một nền tảng khác để tìm cách để tránh rơi vào bất kỳ cạm bẫy hiệu suất?

+1

Tại sao không chạy điểm chuẩn vi mô của riêng bạn để kiểm tra ? Bạn có thể liên kết đến các nguồn có nội dung có hiệu suất "xấu" không? – Oded

+0

@Oded: nguồn là nhận xét của Danny Chen tại đây http://stackoverflow.com/questions/3474254/how-to-make-a-first-letter-capital-in-c/3474263#3474263; thành thật mà nói tôi sẽ ngạc nhiên nếu 'Substring' không phải là' O (1) 'hoạt động thời gian và không gian (như Java), nhưng tôi cho anh ta lợi ích của sự nghi ngờ vì tôi không biết .NET. – polygenelubricants

+1

"hiệu suất kém" nghĩa là gì? So với cái gì? .NET cũng có hiệu suất kém nếu so sánh với C++ chẳng hạn. Chúng ta có nên thả .NET vì điều đó không? –

Trả lời

11

Trong .NET, Substring là O (n) chứ không phải là O (1) của Java. Điều này là bởi vì trong .NET, đối tượng String chứa tất cả dữ liệu ký tự thực tế chính nó - do đó, lấy một chuỗi con liên quan đến việc sao chép tất cả dữ liệu trong chuỗi con mới. Trong Java, substring chỉ có thể tạo một đối tượng mới đề cập đến mảng char ban đầu, với chỉ số bắt đầu và độ dài khác nhau.

Có ưu và nhược điểm của từng phương pháp:

  • cách tiếp cận NET của có bộ nhớ cache sự liên lạc tốt hơn, tạo ra ít đối tượng , và tránh các tình huống mà một chuỗi con nhỏ ngăn cản rất lớn char[] là thu gom rác thải . Tôi tin rằng trong một số trường hợp nó có thể làm cho interop rất dễ dàng quá, nội bộ.
  • cách tiếp cận của Java làm cho tham gia một chuỗi rất hiệu quả, và có lẽ một số các hoạt động khác quá

Có một ít chi tiết hơn trong strings article tôi. Đối với câu hỏi chung về tránh các cạm bẫy hiệu suất, tôi nghĩ rằng tôi nên có câu trả lời soạn sẵn sàng để cắt và dán: đảm bảo kiến ​​trúc của bạn hiệu quả và triển khai theo cách dễ đọc nhất có thể. Đo lường hiệu suất và tối ưu hóa nơi bạn tìm thấy tắc nghẽn.


Ngẫu nhiên, điều này làm cho string rất đặc biệt - đó là chỉ loại không cho mảng có bộ nhớ thay đổi theo thẩm trong thời hạn CLR cùng.

Đối với các chuỗi nhỏ, đây là một chiến thắng lớn. Thật tệ khi có tất cả các chi phí của một đối tượng, nhưng khi có thêm một mảng liên quan, một chuỗi ký tự đơn có thể mất khoảng 36 byte trong Java. (Đó là số "ngón tay trong không trung" - Tôi không thể nhớ chi phí chính xác của đối tượng. Nó cũng sẽ phụ thuộc vào VM bạn đang sử dụng.)

2

Sử dụng phản xạ này là những gì bạn nhận được từ xâu (Int32, Int32)

[SecuritySafeCritical, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
public string Substring(int startIndex, int length) 
{ 
    return this.InternalSubStringWithChecks(startIndex, length, false); 
} 

nếu bạn tiếp tục đi bên cuộc gọi cuối cùng là một

internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount) 

sao chép các ký tự bằng con trỏ. Mã hoàn chỉnh thực sự trông rất lớn nhưng bạn sẽ không thấy tốc độ nhanh hay chậm cho đến khi bạn chạy và kiểm tra nó.

0

Nó thực sự phụ thuộc vào khối lượng công việc của bạn. Nếu bạn đang lặp và thực hiện nhiều cuộc gọi chuỗi con, thì bạn có thể gặp sự cố. Đối với bài viết SO bạn đang đề cập đến, tôi nghi ngờ nó sẽ bao giờ là một vấn đề. Tuy nhiên, với thái độ đó, bạn luôn có thể bật lên trong một tình huống "chết bằng một nghìn lần cắt giấy". Trong SO gửi bạn tham khảo, chúng tôi đã điều sau đây:

String after = before.Substring(0, 1).ToUpper() + before.Substring(1); 

Giả sử các trình biên dịch không làm một số tối ưu hóa điên, điều này sẽ tạo ra ít nhất bốn chuỗi mới (2 Substring cuộc gọi, cuộc gọi ToUpper, và ghép nối). Chuỗi con được thực hiện chính xác như bạn mong muốn (chuỗi sao chép), nhưng ba trong số những chuỗi được phân bổ ở trên sẽ nhanh chóng trở thành rác. Làm nhiều việc này sẽ tạo ra áp lực bộ nhớ không cần thiết. Tôi nói "không cần thiết" bởi vì bạn có thể có thể đưa ra một giải pháp kinh tế hơn chỉ với một ít thời gian đầu tư hơn.

Cuối cùng, các hồ sơ là bạn thân nhất của bạn :)