SlideShare uma empresa Scribd logo
1 de 25
Baixar para ler offline
Python 中 += 與
join比較
高國棟
演講經歷
● 2013/04 在 taipei.py 演講關於 pdb 的實作。相關投影片:
http://www.slideshare.net/ya790026/recoverpdb
● 2013/05 在 pyconf.tw 演將 CPython 原始碼解析。相關投
影片:http://www.slideshare.net/ya790026/c-python23247730。
● 2013/08 在taipei.py 演講 python 如何執行程式碼。相關
投影片:http://www.slideshare.net/ya790026/python27854881
實驗與觀察
● https://gist.github.com/ya790206/7496787
在 windows, linux, mac 下,呈現的結果有時 join 快,有時 +=
快, why?
pep8
For example, do not rely on CPython's efficient
implementation of in-place string concatenation for
statements in the form a += b or a = a + b. This
optimization is fragile even in CPython (it only works for
some types) and isn't present at all in implementations that
don't use refcounting. In performance sensitive parts of the
library, the ''.join() form should be used instead. This will
ensure that concatenation occurs in linear time across
various implementations.
What is fragile ?
+=
● += 的 opcode 是 INPLACE_ADD
● + 的 opcode 是 BINARY_ADD
● 執行字串加法是靠 x = string_concatenate(v,
w, f, next_instr);
● Python/ceval.c
string_concatenate
if (v->ob_refcnt == 1 && !PyString_CHECK_INTERNED(v)) {
if (_PyString_Resize(&v, new_len) != 0) {
return NULL;
}
memcpy(PyString_AS_STRING(v) + v_len,
PyString_AS_STRING(w), w_len);
return v;
}
else {
PyString_Concat(&v, w);
return v;
}

https://github.com/ya790206/CPython/blob/master/Python/ceval.c#L4836
PyString_Concat
void
PyString_Concat(register PyObject **pv, register PyObject *w)
{
register PyObject *v;
if (*pv == NULL)
return;
if (w == NULL || !PyString_Check(*pv)) {
Py_CLEAR(*pv);
return;
}
v = string_concat((PyStringObject *) *pv, w);
Py_DECREF(*pv);
*pv = v;
}

https://github.com/ya790206/CPython/blob/master/Objects/stringobject.c#L3856
string_concat
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
if (op == NULL)
return PyErr_NoMemory();
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
Py_MEMCPY(op->ob_sval, a->ob_sval, Py_SIZE(a));
Py_MEMCPY(op->ob_sval + Py_SIZE(a), b->ob_sval, Py_SIZE(b));
op->ob_sval[size] = '0';
return (PyObject *) op;

https://github.com/ya790206/CPython/blob/master/Objects/stringobject.c#L1014
_PyString_Resize
● defined in Objects/stringobject.c
● it called PyObject_REALLOC
● _PyString_Resize -> PyObject_REALLOC
(Include/objimp.h) -> PyObject_Realloc
(Objects/obmalloc.c)
PyObject_Realloc
return realloc(p, nbytes);

https://github.com/ya790206/CPython/blob/master/Objects/obmalloc.c#L1176
uClibc 的 realloc
if (new_size > size)
/* Grow the block. */
{
size_t extra = new_size - size;
__heap_lock (&__malloc_heap_lock);
extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);
__heap_unlock (&__malloc_heap_lock);
if (extra)
/* Record the changed size. */
MALLOC_SET_SIZE (base_mem, size + extra);
else
/* Our attempts to extend MEM in place failed, just
allocate-and-copy. */
{
void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);
if (new_mem)
{
memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);
free (mem);
}
mem = new_mem;
}
}
https://github.com/ya790206/ext_c_lib/blob/master/uClibc-0.9.33/libc/stdlib/malloc/realloc.c#L24
glibc 的 realloc
if (chunk_is_mmapped(oldp))
{
void* newmem;

#if HAVE_MREMAP
newp = mremap_chunk(oldp, nb);
if(newp) return chunk2mem(newp);
#endif
/* Note the extra SIZE_SZ overhead. */
if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
/* Must alloc, copy, free. */
newmem = __libc_malloc(bytes);
if (newmem == 0) return 0; /* propagate failure */
MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
munmap_chunk(oldp);
return newmem;
}
https://github.com/ya790206/ext_c_lib/blob/master/glibc-2.18/malloc/malloc.c#L2908
glibc 的 realloc
/* Note the extra SIZE_SZ overhead. */
if(oldsize - SIZE_SZ >= nb)
newmem = oldmem; /* do nothing */
else {
/* Must alloc, copy, free. */
if (top_check() >= 0)
newmem = _int_malloc(&main_arena, bytes+1);
if (newmem) {
MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
munmap_chunk(oldp);
}
}
https://github.com/ya790206/ext_c_lib/blob/master/glibc-2.18/malloc/hooks.c#L290
複雜度分析
問: n 個長度為 m 的字串相加,在最糟糕的情形
下,其複雜度?
答:
● 使用 join ,複雜度為 O(nm)
● 使用 +=,其複雜度為 f(n) = f(n-1) + nm
= O(n 2m)
複雜度分析
問: n 個長度為 m 的字串相加,在最佳的情形下,
其複雜度?
答:
● 使用 join ,複雜度為 O(nm)
● 使用 +=,其複雜度為 O(nm)
一開始,join是在慢什麼?
1. 執行字串的 INPLACE_ADD 比
CALL_FUNCTION(append) 快多了。
2. python list 的實作與 c++ vector相似。當 list
空間不夠時,會將 list 搬到可以滿足新大小的
地方
list resize
● list_resize(Object/listobject.c) ->
PyMem_RESIZE(Include/pymem.h)->
PyMem_REALLOC(Include/pymem.h)->
PyMem_REALLOC(Include/pymem.h)->
realloc
為什麼 join 可以後來居上?
● list 要空間是越要越大。4, 8, 16, 25, 35, 46,
58, 72, 88, …
● list 只存指標,因此每次搬家只需複製 (現在
list 大小 * 指標大小) 個bytes
結論
● 如果 realloc 不是回傳新的記憶體位址,則 +=
會很有效率,因為減少一次 memcpy,而且呼
叫字串加法比呼叫 list 的 append 快。
● 在程序的記憶體破碎 (memory fragment) 情
形還沒很嚴重時,realloc比較不容易回傳新的
位址。
結論
● 使用 join 會比 += 好,因為 join 的效能是可以
預期的(使用 +=,你的程序可能執行越久,效
能越差)。
● 如果你想要使用 += 的最佳化,則可以考慮在
新建的程序執行。新建的程序不會有記憶體破
碎問題,但是新建程序會有額外成本。
● += 和 + 的效能一樣。
工商時間
●

PyConf 場務徵人
Question
Thank you

Mais conteúdo relacionado

Semelhante a Python 中 += 與 join比較

Django development
Django developmentDjango development
Django developmentloveyudu
 
20201024_aigo_lab2_fruit_classification_omnixri
20201024_aigo_lab2_fruit_classification_omnixri20201024_aigo_lab2_fruit_classification_omnixri
20201024_aigo_lab2_fruit_classification_omnixriOmniXRI Studio
 
Objc under the_hood_2013
Objc under the_hood_2013Objc under the_hood_2013
Objc under the_hood_2013Michael Pan
 
组件交互模式的非主流研究
组件交互模式的非主流研究组件交互模式的非主流研究
组件交互模式的非主流研究youalab
 
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘Liu Allen
 
初試雲端Python編程:利用Google CoLab平台
初試雲端Python編程:利用Google CoLab平台初試雲端Python編程:利用Google CoLab平台
初試雲端Python編程:利用Google CoLab平台Patrick Ho
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法crasysatan
 
Vue 和 Angular 開發習慣
Vue 和 Angular 開發習慣Vue 和 Angular 開發習慣
Vue 和 Angular 開發習慣Poy Chang
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代scott liao
 
大家應該都要會的工具 Git 從放棄到會用1-基礎篇
大家應該都要會的工具 Git   從放棄到會用1-基礎篇大家應該都要會的工具 Git   從放棄到會用1-基礎篇
大家應該都要會的工具 Git 從放棄到會用1-基礎篇Alan Tsai
 
dbug in mysql
dbug in mysqldbug in mysql
dbug in mysqlTim Chou
 
Gobject - Inherit (Chinese)
Gobject - Inherit (Chinese)Gobject - Inherit (Chinese)
Gobject - Inherit (Chinese)Kai-Feng Chou
 
嵌入式測試驅動開發
嵌入式測試驅動開發嵌入式測試驅動開發
嵌入式測試驅動開發hugo lu
 
分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏Shaoning Pan
 
Deep learning hardware architecture and software deploy with docker
Deep learning hardware architecture and software deploy with dockerDeep learning hardware architecture and software deploy with docker
Deep learning hardware architecture and software deploy with dockerYa-Lun Li
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用勇浩 赖
 
C++工程实践
C++工程实践C++工程实践
C++工程实践Shuo Chen
 
程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號鍾誠 陳鍾誠
 
程式人雜誌 2015年五月
程式人雜誌 2015年五月程式人雜誌 2015年五月
程式人雜誌 2015年五月鍾誠 陳鍾誠
 

Semelhante a Python 中 += 與 join比較 (20)

Django development
Django developmentDjango development
Django development
 
20201024_aigo_lab2_fruit_classification_omnixri
20201024_aigo_lab2_fruit_classification_omnixri20201024_aigo_lab2_fruit_classification_omnixri
20201024_aigo_lab2_fruit_classification_omnixri
 
Objc under the_hood_2013
Objc under the_hood_2013Objc under the_hood_2013
Objc under the_hood_2013
 
组件交互模式的非主流研究
组件交互模式的非主流研究组件交互模式的非主流研究
组件交互模式的非主流研究
 
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
 
Git入門介紹
Git入門介紹Git入門介紹
Git入門介紹
 
初試雲端Python編程:利用Google CoLab平台
初試雲端Python編程:利用Google CoLab平台初試雲端Python編程:利用Google CoLab平台
初試雲端Python編程:利用Google CoLab平台
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法
 
Vue 和 Angular 開發習慣
Vue 和 Angular 開發習慣Vue 和 Angular 開發習慣
Vue 和 Angular 開發習慣
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
 
大家應該都要會的工具 Git 從放棄到會用1-基礎篇
大家應該都要會的工具 Git   從放棄到會用1-基礎篇大家應該都要會的工具 Git   從放棄到會用1-基礎篇
大家應該都要會的工具 Git 從放棄到會用1-基礎篇
 
dbug in mysql
dbug in mysqldbug in mysql
dbug in mysql
 
Gobject - Inherit (Chinese)
Gobject - Inherit (Chinese)Gobject - Inherit (Chinese)
Gobject - Inherit (Chinese)
 
嵌入式測試驅動開發
嵌入式測試驅動開發嵌入式測試驅動開發
嵌入式測試驅動開發
 
分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏
 
Deep learning hardware architecture and software deploy with docker
Deep learning hardware architecture and software deploy with dockerDeep learning hardware architecture and software deploy with docker
Deep learning hardware architecture and software deploy with docker
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用
 
C++工程实践
C++工程实践C++工程实践
C++工程实践
 
程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號
 
程式人雜誌 2015年五月
程式人雜誌 2015年五月程式人雜誌 2015年五月
程式人雜誌 2015年五月
 

Mais de kao kuo-tung

用 Open source 改造鍵盤
用 Open source 改造鍵盤用 Open source 改造鍵盤
用 Open source 改造鍵盤kao kuo-tung
 
Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例kao kuo-tung
 
Openstack swift, how does it work?
Openstack swift, how does it work?Openstack swift, how does it work?
Openstack swift, how does it work?kao kuo-tung
 
Why is a[1] fast than a.get(1)
Why is a[1]  fast than a.get(1)Why is a[1]  fast than a.get(1)
Why is a[1] fast than a.get(1)kao kuo-tung
 
減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法kao kuo-tung
 
Openstack taskflow 簡介
Openstack taskflow 簡介Openstack taskflow 簡介
Openstack taskflow 簡介kao kuo-tung
 
Async: ways to store state
Async:  ways to store stateAsync:  ways to store state
Async: ways to store statekao kuo-tung
 
Docker 原理與實作
Docker 原理與實作Docker 原理與實作
Docker 原理與實作kao kuo-tung
 
那些年,我們一起看的例外
那些年,我們一起看的例外那些年,我們一起看的例外
那些年,我們一起看的例外kao kuo-tung
 
Garbage collection 介紹
Garbage collection 介紹Garbage collection 介紹
Garbage collection 介紹kao kuo-tung
 
Python 如何執行
Python 如何執行Python 如何執行
Python 如何執行kao kuo-tung
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片kao kuo-tung
 

Mais de kao kuo-tung (15)

用 Open source 改造鍵盤
用 Open source 改造鍵盤用 Open source 改造鍵盤
用 Open source 改造鍵盤
 
Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例
 
Python to scala
Python to scalaPython to scala
Python to scala
 
Intorduce to Ceph
Intorduce to CephIntorduce to Ceph
Intorduce to Ceph
 
Openstack swift, how does it work?
Openstack swift, how does it work?Openstack swift, how does it work?
Openstack swift, how does it work?
 
Why is a[1] fast than a.get(1)
Why is a[1]  fast than a.get(1)Why is a[1]  fast than a.get(1)
Why is a[1] fast than a.get(1)
 
減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法
 
Openstack taskflow 簡介
Openstack taskflow 簡介Openstack taskflow 簡介
Openstack taskflow 簡介
 
Async: ways to store state
Async:  ways to store stateAsync:  ways to store state
Async: ways to store state
 
Openstack 簡介
Openstack 簡介Openstack 簡介
Openstack 簡介
 
Docker 原理與實作
Docker 原理與實作Docker 原理與實作
Docker 原理與實作
 
那些年,我們一起看的例外
那些年,我們一起看的例外那些年,我們一起看的例外
那些年,我們一起看的例外
 
Garbage collection 介紹
Garbage collection 介紹Garbage collection 介紹
Garbage collection 介紹
 
Python 如何執行
Python 如何執行Python 如何執行
Python 如何執行
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片
 

Python 中 += 與 join比較

  • 1. Python 中 += 與 join比較 高國棟
  • 2. 演講經歷 ● 2013/04 在 taipei.py 演講關於 pdb 的實作。相關投影片: http://www.slideshare.net/ya790026/recoverpdb ● 2013/05 在 pyconf.tw 演將 CPython 原始碼解析。相關投 影片:http://www.slideshare.net/ya790026/c-python23247730。 ● 2013/08 在taipei.py 演講 python 如何執行程式碼。相關 投影片:http://www.slideshare.net/ya790026/python27854881
  • 3.
  • 4. 實驗與觀察 ● https://gist.github.com/ya790206/7496787 在 windows, linux, mac 下,呈現的結果有時 join 快,有時 += 快, why?
  • 5. pep8 For example, do not rely on CPython's efficient implementation of in-place string concatenation for statements in the form a += b or a = a + b. This optimization is fragile even in CPython (it only works for some types) and isn't present at all in implementations that don't use refcounting. In performance sensitive parts of the library, the ''.join() form should be used instead. This will ensure that concatenation occurs in linear time across various implementations.
  • 7. += ● += 的 opcode 是 INPLACE_ADD ● + 的 opcode 是 BINARY_ADD ● 執行字串加法是靠 x = string_concatenate(v, w, f, next_instr); ● Python/ceval.c
  • 8. string_concatenate if (v->ob_refcnt == 1 && !PyString_CHECK_INTERNED(v)) { if (_PyString_Resize(&v, new_len) != 0) { return NULL; } memcpy(PyString_AS_STRING(v) + v_len, PyString_AS_STRING(w), w_len); return v; } else { PyString_Concat(&v, w); return v; } https://github.com/ya790206/CPython/blob/master/Python/ceval.c#L4836
  • 9. PyString_Concat void PyString_Concat(register PyObject **pv, register PyObject *w) { register PyObject *v; if (*pv == NULL) return; if (w == NULL || !PyString_Check(*pv)) { Py_CLEAR(*pv); return; } v = string_concat((PyStringObject *) *pv, w); Py_DECREF(*pv); *pv = v; } https://github.com/ya790206/CPython/blob/master/Objects/stringobject.c#L3856
  • 10. string_concat op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size); if (op == NULL) return PyErr_NoMemory(); PyObject_INIT_VAR(op, &PyString_Type, size); op->ob_shash = -1; op->ob_sstate = SSTATE_NOT_INTERNED; Py_MEMCPY(op->ob_sval, a->ob_sval, Py_SIZE(a)); Py_MEMCPY(op->ob_sval + Py_SIZE(a), b->ob_sval, Py_SIZE(b)); op->ob_sval[size] = '0'; return (PyObject *) op; https://github.com/ya790206/CPython/blob/master/Objects/stringobject.c#L1014
  • 11. _PyString_Resize ● defined in Objects/stringobject.c ● it called PyObject_REALLOC ● _PyString_Resize -> PyObject_REALLOC (Include/objimp.h) -> PyObject_Realloc (Objects/obmalloc.c)
  • 13. uClibc 的 realloc if (new_size > size) /* Grow the block. */ { size_t extra = new_size - size; __heap_lock (&__malloc_heap_lock); extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra); __heap_unlock (&__malloc_heap_lock); if (extra) /* Record the changed size. */ MALLOC_SET_SIZE (base_mem, size + extra); else /* Our attempts to extend MEM in place failed, just allocate-and-copy. */ { void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE); if (new_mem) { memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE); free (mem); } mem = new_mem; } } https://github.com/ya790206/ext_c_lib/blob/master/uClibc-0.9.33/libc/stdlib/malloc/realloc.c#L24
  • 14. glibc 的 realloc if (chunk_is_mmapped(oldp)) { void* newmem; #if HAVE_MREMAP newp = mremap_chunk(oldp, nb); if(newp) return chunk2mem(newp); #endif /* Note the extra SIZE_SZ overhead. */ if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */ /* Must alloc, copy, free. */ newmem = __libc_malloc(bytes); if (newmem == 0) return 0; /* propagate failure */ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); munmap_chunk(oldp); return newmem; } https://github.com/ya790206/ext_c_lib/blob/master/glibc-2.18/malloc/malloc.c#L2908
  • 15. glibc 的 realloc /* Note the extra SIZE_SZ overhead. */ if(oldsize - SIZE_SZ >= nb) newmem = oldmem; /* do nothing */ else { /* Must alloc, copy, free. */ if (top_check() >= 0) newmem = _int_malloc(&main_arena, bytes+1); if (newmem) { MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); munmap_chunk(oldp); } } https://github.com/ya790206/ext_c_lib/blob/master/glibc-2.18/malloc/hooks.c#L290
  • 16. 複雜度分析 問: n 個長度為 m 的字串相加,在最糟糕的情形 下,其複雜度? 答: ● 使用 join ,複雜度為 O(nm) ● 使用 +=,其複雜度為 f(n) = f(n-1) + nm = O(n 2m)
  • 17. 複雜度分析 問: n 個長度為 m 的字串相加,在最佳的情形下, 其複雜度? 答: ● 使用 join ,複雜度為 O(nm) ● 使用 +=,其複雜度為 O(nm)
  • 18. 一開始,join是在慢什麼? 1. 執行字串的 INPLACE_ADD 比 CALL_FUNCTION(append) 快多了。 2. python list 的實作與 c++ vector相似。當 list 空間不夠時,會將 list 搬到可以滿足新大小的 地方
  • 19. list resize ● list_resize(Object/listobject.c) -> PyMem_RESIZE(Include/pymem.h)-> PyMem_REALLOC(Include/pymem.h)-> PyMem_REALLOC(Include/pymem.h)-> realloc
  • 20. 為什麼 join 可以後來居上? ● list 要空間是越要越大。4, 8, 16, 25, 35, 46, 58, 72, 88, … ● list 只存指標,因此每次搬家只需複製 (現在 list 大小 * 指標大小) 個bytes
  • 21. 結論 ● 如果 realloc 不是回傳新的記憶體位址,則 += 會很有效率,因為減少一次 memcpy,而且呼 叫字串加法比呼叫 list 的 append 快。 ● 在程序的記憶體破碎 (memory fragment) 情 形還沒很嚴重時,realloc比較不容易回傳新的 位址。
  • 22. 結論 ● 使用 join 會比 += 好,因為 join 的效能是可以 預期的(使用 +=,你的程序可能執行越久,效 能越差)。 ● 如果你想要使用 += 的最佳化,則可以考慮在 新建的程序執行。新建的程序不會有記憶體破 碎問題,但是新建程序會有額外成本。 ● += 和 + 的效能一樣。