2010-05-06 36 views
10

Trong chương trình tôi viết, tôi đang thực hiện rất nhiều thao tác chuỗi. Tôi đang cố gắng để tăng hiệu suất và đang tự hỏi nếu sử dụng mảng char sẽ cho thấy một sự gia tăng hiệu suất khá. Bất kỳ đề xuất?Chuỗi tối ưu hóa Java so với mảng Char

+0

@ ThePinkPoo: câu hỏi của bạn thiếu các yêu cầu: Chuỗi của bạn phải chứa gì? Toàn bộ phạm vi của Unicode (trong trường hợp sử dụng char [] sẽ chứng minh là một nỗi đau lớn vì một char * * * * ** HOÀN THÀNH INADEQUATE ** đại diện cho các codepoint Unicode mới được giới thiệu trong Unicode 3.1 trở lên)? Chỉ (một tập hợp con) ASCII? Trong trường hợp thứ hai, bạn có thể thực hiện lại toàn bộ lớp String chỉ được hỗ trợ bởi các byte và rất nhiều * tối ưu hóa * rất tiện lợi có thể được thực hiện. Đã ở đó, thực hiện điều đó, xử lý hàng trăm megabyte tệp văn bản ASCII trong Java ... – SyntaxT3rr0r

Trả lời

7

Loại thao tác nào bạn đang làm? Bạn có thể gửi mẫu mã không?

Bạn có thể muốn xem StringBuilder triển khai CharSequence để cải thiện hiệu suất. Tôi không chắc chắn bạn muốn cuộn của riêng bạn. StringBuilder không phải là btw an toàn chủ đề ... nếu bạn muốn xem xét an toàn chủ đề tại StringBuffer.

+0

Nếu bạn cần an toàn luồng, có một cơ hội không nhỏ nhặt bạn sẽ phải làm nhiều hơn là chỉ cần thả một 'StringBuffer'. Bạn có thể tránh deadlocks và điều kiện chủng tộc, nhưng kết quả có thể sẽ không phù hợp với những gì bạn đang mong đợi. –

+0

Cảm ơn bạn tôi sẽ triển khai lại và sau đó đăng kết quả của mình. – ThePinkPoo

+0

@Hank: Với một bản cập nhật không nhỏ, bạn quấn 'sync (thebuffer) {...} 'của riêng bạn, nhưng bạn không cần những thứ đó quá thường xuyên. Thật vậy, đó là lý do tại sao 'StringBuilder' được giới thiệu; để loại bỏ các chi phí giữ khóa ở tất cả khi nó không cần thiết (tức là, hầu như tất cả các thời gian). –

2

Chuỗi đã được triển khai dưới dạng mảng char. Bạn định làm gì khác? Dù sao, giữa đó và thực tế là GC cho các đối tượng không lâu là cực kỳ nhanh chóng tôi sẽ ngạc nhiên nếu bạn có thể tìm thấy một cách để tăng hiệu suất bằng cách thay thế mảng char.

Lời khuyên của Michael Borgwardt về mảng char nhỏ và sử dụng StringBuilder và StringBuffer rất tốt. Nhưng với tôi điều chính là cố gắng không đoán về những gì chậm: thực hiện các phép đo, sử dụng một hồ sơ, nhận được một số sự kiện nhất định. Bởi vì thông thường, các dự đoán của chúng tôi về hiệu suất hóa ra là sai.

1

Khi bạn có một số lượng lớn các chuỗi ngắn, sử dụng char[] thay vì có thể tiết kiệm khá nhiều bộ nhớ, điều này cũng có nghĩa là tốc độ nhanh hơn do thiếu bộ nhớ cache.

Nhưng với các chuỗi lớn, điều chính cần chú ý là tránh sao chép không cần thiết dẫn đến sự bất biến của String. Nếu bạn làm nhiều nối hoặc thay thế, sử dụng StringBuilder có thể tạo ra sự khác biệt lớn.

+0

Michael, bạn có thể xây dựng thêm một chút về việc thay thế Strings bằng char [] không? Char [] sẽ chiếm ít không gian hơn so với String instance, tuy nhiên char [] không nhận được nội bộ và cho nhiều chuỗi ngắn xác suất rằng một số chuỗi giống nhau và sẽ được internalized (tức là JVM sẽ giữ một bản sao) cao hơn nhiều so với một vài chuỗi dài. –

+0

@Totophil: Nó thực sự phụ thuộc vào loại Strings bạn làm việc và những gì bạn làm với chúng; Nếu bạn sử dụng các biểu diễn có thể thay đổi được, việc thực tập trở nên không liên quan. –

+0

Michael, đồng ý, nó thực sự phụ thuộc vào các chi tiết cụ thể của kịch bản. Và kịch bản duy nhất xuất hiện trong đầu tôi là khi phần mềm cần thực hiện rất nhiều thao tác chuỗi "tại chỗ". Nhưng cách tiếp cận này sẽ không giúp ích gì cho việc giải quyết các khoản chi phí của chuỗi từ việc nối, tìm kiếm và so sánh. –

2

Dưới đây là một đoạn trích từ full source of String class từ JDK 6.0:

public final class String implements java.io.Serializable, 
     Comparable<String>, CharSequence { 
     /** The value is used for character storage. */ 
     private final char value[]; 

     /** The offset is the first index of the storage that is used. */ 
     private final int offset; 

     /** The count is the number of characters in the String. */ 
     private final int count; 

Như bạn thấy trong nội bộ các giá trị đã được lưu trữ như là một mảng của chars. Một mảng các ký tự như là một cấu trúc dữ liệu có tất cả các hạn chế của lớp String đối với hầu hết các thao tác chuỗi: các mảng Java không phát triển, tức là mỗi lần (ok, có thể không phải mỗi lần) chuỗi của bạn sẽ cần phát triển mà bạn cần để phân bổ một mảng mới và sao chép nội dung.

Như đã đề xuất trước đó, bạn nên sử dụng StringBuilder hoặc StringBuffer cho hầu hết các thao tác chuỗi.

Trong thực tế đoạn mã sau:

String a = "a"; 
    a=a+"b"; 
    a=a+"c"; 

Khi biên soạn sẽ được tự động chuyển đổi sang sử dụng StringBuilder, điều này có thể dễ dàng kiểm tra với sự giúp đỡ của javap. Theo quy tắc, hiếm khi bạn nên dành thời gian cố gắng cải thiện hiệu suất của các lớp Java cốt lõi, trừ khi bạn là chuyên gia đẳng cấp thế giới về vấn đề này, đơn giản là vì mã này được viết bởi các chuyên gia đẳng cấp thế giới trong địa điểm đầu tiên.

2

Bạn đã lược tả đơn đăng ký của mình chưa? Bạn có biết các nút cổ chai ở đâu không? Đó là bước đầu tiên nếu hiệu suất là phụ mệnh. Vâng, đó và xác định các chỉ số hiệu suất được chấp nhận là gì.

Khi bạn đã lược tả thực hiện một số tác vụ, bạn sẽ có phần trăm thời gian dành cho công việc. Nếu bạn dành nhiều thời gian thao tác Strings, có thể bạn có thể bắt đầu cache một số thao tác đó?Bạn đang làm một số người trong số họ nhiều lần khi làm cho họ chỉ một lần sẽ đủ (và sau đó sử dụng kết quả đó một lần nữa sau khi nó là cần thiết)? Bạn đang sao chép Strings khi bạn không cần phải? Hãy nhớ rằng, java.lang.String là không thay đổi - vì vậy nó không thể thay đổi trực tiếp.

Tôi đã tìm thấy nhiều lần trong khi tối ưu hóa/hiệu suất tinh chỉnh hệ thống tôi làm việc trên đó tôi không biết nơi chậm đi đến từ bản năng. Tôi đã thấy những người khác (và, đáng xấu hổ, bản thân mình) dành nhiều ngày để tối ưu hóa một cái gì đó cho thấy không đạt được - bởi vì nó không phải là nút cổ chai ban đầu, và trên thực tế ít hơn 1% thời gian.

Hy vọng điều này sẽ giúp bạn đi đúng hướng.

+0

Tôi đã lược tả và nó không quá nhiều thông tin vì sự phức tạp của tôi là khá nhỏ. Tôi biết từ hồ sơ rằng các phương pháp chuỗi đã giết chết nó, cũng là vòng của tôi trong mã. Vì vậy, tôi sẽ unroll một số các vòng và sử dụng StringBuilder – ThePinkPoo

+0

@ ThePinkPoo: Nếu các hoạt động String đang giết chết nó, sau đó điều tốt nhất để làm là cố gắng và giảm số lượng các hoạt động String bạn đang làm. Điều này có thể được thực hiện thông qua bộ nhớ đệm hoặc hành vi tương tự. Xin lỗi vì giả sử bạn không có hồ sơ - Tôi thường thấy rằng trên các trang phong cách diễn đàn khác nhau (ở đây được bao gồm) và muốn đảm bảo rằng bạn đã làm việc đó. :) Chúc may mắn. – aperkins