Re: [問題] a[1:3]會馬上複製嗎?

作者: why8ther (外八喵)   2015-07-22 10:27:49
※ 引述《why8ther (外八喵)》之銘言:
: 已知:
: b = [2, 3]
: >>> b[0] = 99
: b = [99, 3]
: a = [1, 2, 3, 4]
: 由此可知,黃色那行的值並不會改動到a陣列,而是創造一個副本了
: 我的問題是 :
: 這個副本是(1) 在我呼叫a[1:3]時就被創造了?
: 抑或(2) 直到我改動b[0]才被創造,若不改動就永遠參照本來陣列
: 因為最近遇到比較高的性能要求 需要弄清楚@@
: 第一次po文 請大家多多指教
自己回自己的文XDD
其實應該是有實作copy on write的
根據這篇stack overflow http://goo.gl/XcgHG6
我自己實驗也是一樣的結果
>>> a = [1,2,3]
>>> b = a[1:3]
>>> id(a[1])
1440535008
>>> id(b[0])
1440535008
>>> b[0] = 123
>>> a
[1, 2, 3]
>>> b
[123, 3]
>>> id(a[1])
1440535008
>>> id(b[0])
1440536944 變得不一樣了!!
>>> id(a[2])
1440535024
>>> id(b[1]) 但a[2]和b[1]沒有被改動,仍是同一個
1440535024
不過雖說是copy on write,但我推測應該還是複製了陣列中每個元素的referance
而不只是陣列本身的referance
推測根據就是上面那行紅字。
若本來陣列長度是100,就等於複製了100份的參照。
所以比較適合的狀況應該是:
陣列中每個物件很大,但陣列本身較短
反之,若陣列元素很小(像是int)
那複製參照跟直接複製應該就沒啥差別惹。
大概是這樣
作者: LiloHuang (十年一刻)   2015-07-22 10:51:00
http://goo.gl/CpWviL Python 會直接建立新的 list把 reference 拷貝過去,這並不算是 Copy-on-write畢竟拷貝的行為還是產生了,而且並不是在 write 時拷貝所以不能稱之為是完整的 copy-on-write。
作者: uranusjr (←這人是超級笨蛋)   2015-07-22 11:35:00
這根本就不是 copy-on-write, 無所謂完不完整啊你在 C++ 拷貝 list<int *> 也會有類似行為, 但根本不會有人把它叫做 copy-on-write, 因為它就是單純的 copy
作者: LiloHuang (十年一刻)   2015-07-22 11:43:00
我必須要修正我的用語,這不是"真正"的 copy-on-write謝謝 uranusjr 的補充 :)真正的 copy-on-write 是在 write 時拷貝物件,即便是reference 也要在 write 時才被拷貝,而不是一開始拷貝如果有一億個 list elements 搭配 COW,不會有 O(n) 的拷貝成本存在於建立第二份 list 時另外之所以我會用是否"完整"的用詞是維基百科對於 COW的定義,某種策略上是有用指標來只到原始版本的https://goo.gl/HiAM5V 但是我不認為這是真正的COW就是因為真正大家談及的COW,都是像 fork child process在還沒有修改原始版本前,不應該存在有額外的消耗就是或者應該說 C++ 拷貝 list<Foobar *> 假設 Foobar 是成本超高的大物件,在寫入時作出副本,也是某種程度的COW,對於該大物件而言。只是 Python 根本就是建立了新物件,然後把參照給換掉,因為數字是 immutable obj跟 COW 的策略一點關係都沒有,因為新物件不是它建立的真正的 COW 要是全自動的,對使用者來說是透明無感的。另外如同維基百科寫的 std::string 有 COW 實作有空的人不仿可以看看實作方法,我相信是拷貝指標 :P因此用"完整"一詞會更好,完整的COW連指標都不會拷貝但這還是端看實作,跟到底被 COW 的對象是什麼物件而定

Links booklink

Contact Us: admin [ a t ] ucptt.com