Đỗ es .net sử dụng thực tập chuỗi cho mỗi chuỗi mà tôi sử dụng?
Không, nhưng nó sử dụng nó cho những chuỗi mà nó biết về thời gian biên dịch vì chúng là hằng số trong mã.
string x = "abc"; //interned
string y = "ab" + "c"; //interned as the same string because the
//compiler can work out that it's the same as
//y = "abc" at compile time so there's no need
//to do that concatenation at run-time. There's
//also no need for "ab" or "c" to exist in your
//compiled application at all.
string z = new StreamReader(new FileStream(@"C:\myfile.text")).ReadToEnd();
//z isn't interned because it isn't known at compile
//time. Note that @"C:\myfile.text" is interned because
//while we don't have a variable we can access it by
//it is a string in the code.
Nếu vậy, không một điều đau khổ thực hiện?
Không, nó giúp thực hiện:
Đầu tiên: Tất cả những chuỗi sẽ được trong bộ nhớ của ứng dụng ở đâu đó. Thực tập có nghĩa là chúng tôi không có bản sao không cần thiết, vì vậy chúng tôi sử dụng ít bộ nhớ hơn. Thứ hai: Nó làm cho so sánh chuỗi chúng ta biết là từ chuỗi nội bộ chỉ siêu nhanh. Thứ ba: Điều đó không tăng lên nhiều, nhưng sự thúc đẩy nó mang lại những so sánh khác. Hãy xem xét mã này tồn tại trong một trong các trình so sánh được tích hợp sẵn:
public override int Compare(string x, string y)
{
if (object.ReferenceEquals(x, y))
{
return 0;
}
if (x == null)
{
return -1;
}
if (y == null)
{
return 1;
}
return this._compareInfo.Compare(x, y, this._ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
}
Đây là thứ tự, nhưng áp dụng cho kiểm tra bình đẳng/bất bình đẳng. Để kiểm tra hai chuỗi bằng hoặc đặt chúng theo thứ tự yêu cầu chúng ta thực hiện thao tác O (n) trong đó n là tỷ lệ thuận với độ dài của chuỗi (ngay cả trong trường hợp một số bỏ qua và thông minh có thể được thực hiện, nó vẫn tỷ lệ thuận) . Điều này có khả năng làm chậm chuỗi dài và so sánh chuỗi là thứ mà rất nhiều ứng dụng thực hiện rất nhiều thời gian - một nơi tuyệt vời để tăng tốc. Nó cũng chậm nhất cho trường hợp bình đẳng (vì thời điểm chúng ta tìm thấy một sự khác biệt chúng ta có thể trả về một giá trị, nhưng các chuỗi bằng nhau phải được kiểm tra hoàn toàn). Tất cả mọi thứ luôn luôn bằng với ngay cả khi bạn xác định lại những gì "bằng" có nghĩa là (văn bản nhạy cảm, không nhạy cảm, văn hóa khác nhau - mọi thứ vẫn bằng với chính nó và nếu bạn tạo ghi đè Equals()
không tuân theo điều đó, bạn sẽ có lỗi). Tất cả mọi thứ luôn luôn được đặt hàng tại cùng một điểm như một cái gì đó bằng.Điều này có nghĩa là hai điều:
- Chúng tôi luôn có thể cân nhắc điều gì đó tương đương với chính nó mà không thực hiện thêm bất kỳ công việc nào.
- Chúng tôi luôn có thể cung cấp giá trị so sánh của
0
để so sánh nội dung nào đó với chính nó mà không cần thêm bất kỳ công việc nào.
Do đó, mã ở trên cắt ngắn trong trường hợp này mà không phải thực hiện so sánh phức tạp và tốn kém hơn. Ngoài ra còn có không có từ phía xuống kể từ khi chúng tôi đã không bao gồm trường hợp này chúng tôi sẽ phải thêm vào một thử nghiệm cho trường hợp mà cả hai giá trị thông qua nơi null
anyway.
Bây giờ, điều đó xảy ra khi so sánh một cái gì đó với chính nó xuất hiện khá tự nhiên với cách một số thuật toán hoạt động, vì vậy nó luôn có giá trị thực hiện. Tuy nhiên, chuỗi ký tự tăng thời gian khi hai chuỗi chúng ta có trong các giá trị khác nhau (ví dụ: x
và z
ở đầu câu hỏi của bạn), vì vậy nó tăng tần suất cắt ngắn hoạt động cho chúng tôi.
Đó là một tối ưu hóa nhỏ trong hầu hết thời gian, nhưng chúng tôi nhận được nó miễn phí và chúng tôi nhận được nó thường xuyên như vậy là tuyệt vời để có nó. Thực tế takeaway từ này - nếu bạn đang viết một Equals
hoặc một Compare
xem xét liệu bạn cũng nên sử dụng cắt ngắn này.
Câu hỏi liên quan sau đó là "tôi có nên thực tập mọi thứ không?"
Ở đây, chúng tôi phải xem xét nhược điểm mà các chuỗi được biên dịch không có. Interning không bao giờ lãng phí với biên dịch trong chuỗi, bởi vì họ phải ở đâu đó. Tuy nhiên, nếu bạn đọc một chuỗi từ một tập tin, tập trung vào nó, và sau đó không bao giờ sử dụng nó một lần nữa nó sẽ sống một thời gian dài, và đó là lãng phí. Nếu bạn đã làm nó tất cả các thời gian, bạn có thể làm tê liệt sử dụng bộ nhớ của bạn.
Hãy tưởng tượng mặc dù bạn thường xuyên đọc nhiều mục bao gồm một số số nhận dạng. Bạn thường xuyên sử dụng các số nhận dạng này để đối sánh các mục với dữ liệu từ một nguồn khác. Có một bộ định danh nhỏ sẽ từng thấy (chỉ có vài trăm giá trị có thể). Sau đó, bởi vì kiểm tra bình đẳng là những gì các chuỗi này là tất cả về, và không có nhiều người trong số họ, interning (trên cả dữ liệu đọc và dữ liệu bạn so sánh nó với - nó vô nghĩa nếu không) trở thành một chiến thắng. Hoặc, giả sử rằng có một vài nghìn đối tượng như vậy và dữ liệu chúng tôi khớp với nó luôn được lưu trong bộ nhớ - điều đó có nghĩa là các chuỗi đó luôn ở đâu đó trong bộ nhớ, vì vậy việc thực tập trở thành không có trí tuệ thắng lợi. (Trừ khi có khả năng rất nhiều kết quả "không tìm thấy" - thực tập những định danh đó chỉ để không tìm thấy kết quả trùng khớp là mất).
Cuối cùng, cùng một kỹ thuật cơ bản có thể được thực hiện khác nhau. XmlReader
ví dụ các chuỗi cửa hàng mà nó so sánh trong một số NameTable
hoạt động như một hồ bơi thực tập riêng, nhưng toàn bộ điều có thể được thu thập khi hoàn tất. Bạn cũng có thể áp dụng kỹ thuật này cho bất kỳ loại tham chiếu nào sẽ không bị thay đổi trong thời gian được gộp lại (cách tốt nhất để đảm bảo rằng nó không thay đổi được vì vậy nó sẽ không thay đổi trong bất kỳ thời điểm nào). Sử dụng kỹ thuật này với các bộ sưu tập rất lớn với số lượng bản sao lớn có thể giảm thiểu sử dụng bộ nhớ (tiết kiệm lớn nhất của tôi là ít nhất 16GB - có thể nhiều hơn nhưng máy chủ vẫn bị treo vào thời điểm đó trước khi kỹ thuật được áp dụng) và/hoặc tốc độ lên so sánh.
Đọc tốt cho [chuỗi thực tập] (http://blogs.msdn.com/b/ericlippert/archive/2009/09/28/string-interning-and-string-empty.aspx) – V4Vendetta