字元串在各類語言里是怎麼處理的?
題主已知的:
1. C++的 std::string通過 copy on write 技術, 減少拷貝次數. 字元串也是屬於最耗的(好像比O(n)好一些)2. Lua
通過源碼了解過,40個字元是分界點,40個字元內是放全局哈希表,40個以上算長字元串,經過隨機處理的 hash 後存儲。lua 編碼中,字元串不存在拷貝,字元串比較是整數級性能。現在想了解其他語言, 例如Python,PHP,Golang,Rust, Erlang, C#,Java,JavaScript,Swift 等語言的字元串拷貝和比較的性能到底是整數級別的還是類似C/C++那樣的原始字串比較?
相比之下Erlang的字元串處理就要簡單粗暴的多了。
不妨先直接無視各種不常用的情況。
iolist的類型定義可以寫成
-type iolist() :: binary() | [iolist()].
在拼接字元串的時候完全不Copy。直接構造一個新的list就完了。
IOList3 = [IOList1, IOList2].
反正 gen_tcp:send 什麼的都能接受,直接就當 iovec 發出去了嘛。
我就是要把兩個binary拼起來怎麼辦?比如
Bin3 = &<&
std::string真心不是cow的,至少VC的不是
老實講,本人喜歡c++的原因之一就是c++沒有一些內部cow的玩意,cow很煩,超級煩。補個Delphi的
首先,字元串是基本數據結構,由編譯器和運行時支持,不是對象。AnsiString:
引用計數+copy on write字元部分所佔用內存只能在堆上分配
當引用計數為0時銷毀注意,當作為const參數傳入時,不修改引用計數WideString:
之前的描述錯誤,此處已糾正copy on assign ,沒有引用計數和非copy on write與Windows OLE/COM BSTR兼容(或者說就是BSTR),底層調用系統API(如SysAllocString)來管理ShortString:
本質上是自帶長度的限長字元數組棧上堆上皆可字元串和字元數組直接=或&<&>比較時,運行時內部為字元數組轉換為字元串,然後再二進位比較(這一塊rtl和fastcode都是彙編實現的)
如果比較雙方已經都是字元串了,則是直接二進位比較因此一些性能關鍵的應用,如何避免臨時字元串的創建,也是注意事項之一補充一下 Pascal 字元串的一些內容。
ANSIString 作為非常量時分配在堆上,棧或全局區上有一個指針指向首字元。作為常量時分配在全局區,引用數恆定為 -1 。Free Pascal 3.0.0 開始的 ANSIString 和舊版本不一樣了。
新的 ANSIString 在字串本體前面是-15..-14 代碼頁(Word) ——用於不同代碼頁的自動轉換-11 字元位元組數(Byte) ——用於多位元組字元串的處理-7..-4 引用數(LongInt) ——用於 copy on write 的處理-3..0 實際位元組長度(LongInt)
1~實際長度是字元串本體,後面補一個 Char(0) 兼容 C 字元串。舊版本的前置結構沒有代碼頁和字元位元組數。
舊版本程序的對新版本 ANSIString 進行只讀操作時不會出錯。但一旦改動的話,因為堆空間地址頭位置不同,發生重新分配或釋放內存時會出錯。新版本的程序對舊版本 ANSIString 改動時也可能出錯。只讀操作時需要忽略代碼頁的特性才能盡量保證不出錯。UnicodeString 則是舊版本 ANSIString 把字元換成 WideChar 的版本。
WideString 是和微軟的 BSTR 兼容的類型。和 UnicodeString 不同,沒有引用數的結構,也不使用 copy on write 。C++11的std::string沒有使用copy-on-write技術,因為這麼做不滿足標準需求,參見N2668
- Go一段只讀的內存,賦值是淺拷貝,取子串會 share 原字元串的空間。字元串相連是創建新字元串然後拷貝。沒有 builtin 的 interning。
- Java一個 immutable 的 class,賦值是淺拷貝。取子串和字元串相連都需要創建新的 class 並做內存拷貝。有 interning 支持,但不自動做。
Rust 標準庫源碼很好懂 https://doc.rust-lang.org/src/collections/string.rs.html#36-38
pub struct String {
vec: Vec&
}
是一個 UTF-8 字元組成的 Vector (和 C++ 的 Vector 一個東西)
實際上 Rust 和 C++ 這種你可以自己輕鬆地實現一個字元池(HashSet&
一般 Lua Python PHP Ruby JS 這種語言都有類似設施。術語是 String interning。
Python 我記得和 Lua 的實現有點像,短字元串放在全局的池裡面,但是長的字元串我記得是一個獨立的內存空間(記錯的話指出)。C# 的 String.Intern Method (System),Java 也有。我不會 C# 和 Java,這個應該是手動的進行?C#:字元串創造出來之後就不能改了,搞並發的時候效果拔群。
String interning is supported by some modern object-oriented programming languages, including Python, Lua, Ruby (with its symbols), Java and .NET languages. Lisp, Scheme, and Smalltalk are among the languages with a symbol type that are basically interned strings.
via http://en.wikipedia.org/wiki/String_interning
不過誰能告訴我「String interning」的中文翻譯應該是什麼?最近由於項目需要,剛好在看Python裡面string intern相關的資料。
「Python會對短字元串做intern」這句話是很籠統並且也是不準確的。
具體可以看看這篇博客:The internals of Python string interning
如果不想看英文的,可以看我翻譯的中文版:Python string interning原理
pascal:首位存放字元串長度
推薦閱讀:
※為什麼 Win7 CMD 下執行兩條 copy 命令,其中一條會完整匹配擴展名而另一條不會?
※為什麼十年來新興的編程語言,大多是動態類型語言?
※如何將主機上的CVS文件入庫到oracle數據中?
※請問寫SQL腳本的算不算程序員?