Seperti yang dijelaskan oleh orang lain, itu tidak hanya menyalin referensi tetapi juga meningkatkan jumlah referensi di dalam benda-benda dan dengan demikian benda yang diakses dan cache berperan.
Di sini saya hanya ingin menambahkan lebih banyak eksperimen. Tidak begitu banyak tentang shuffled vs unshuffled (di mana mengakses satu elemen mungkin melewatkan cache tetapi memasukkan elemen-elemen berikut ke dalam cache sehingga mereka terkena). Tetapi tentang elemen berulang, di mana akses nanti dari elemen yang sama mungkin mengenai cache karena elemen tersebut masih dalam cache.
Menguji rentang normal:
>>> from timeit import timeit
>>> a = range(10**7)
>>> [timeit(lambda: list(a), number=100) for _ in range(3)]
[5.1915339142808925, 5.1436351868889645, 5.18055115701749]
Daftar dengan ukuran yang sama tetapi dengan hanya satu elemen yang diulang terus-menerus lebih cepat karena selalu menyentuh cache:
>>> a = [0] * 10**7
>>> [timeit(lambda: list(a), number=100) for _ in range(3)]
[4.125743135926939, 4.128927210087596, 4.0941229388550795]
Dan sepertinya tidak masalah berapa jumlahnya:
>>> a = [1234567] * 10**7
>>> [timeit(lambda: list(a), number=100) for _ in range(3)]
[4.124106479141709, 4.156590225249886, 4.219242600790949]
Menariknya, itu menjadi lebih cepat ketika saya malah mengulangi dua atau empat elemen yang sama:
>>> a = [0, 1] * (10**7 / 2)
>>> [timeit(lambda: list(a), number=100) for _ in range(3)]
[3.130586101607932, 3.1001001764957294, 3.1318465707127814]
>>> a = [0, 1, 2, 3] * (10**7 / 4)
>>> [timeit(lambda: list(a), number=100) for _ in range(3)]
[3.096105435911994, 3.127148431279352, 3.132872673690855]
Saya kira ada sesuatu yang tidak suka penghitung tunggal yang sama meningkat sepanjang waktu. Mungkin beberapa jalur pipa terhenti karena setiap kenaikan harus menunggu hasil dari peningkatan sebelumnya, tetapi ini adalah tebakan liar.
Bagaimanapun, coba ini untuk jumlah elemen berulang yang lebih besar:
from timeit import timeit
for e in range(26):
n = 2**e
a = range(n) * (2**25 / n)
times = [timeit(lambda: list(a), number=20) for _ in range(3)]
print '%8d ' % n, ' '.join('%.3f' % t for t in times), ' => ', sum(times) / 3
Outputnya (kolom pertama adalah jumlah elemen yang berbeda, untuk setiap saya menguji tiga kali dan kemudian mengambil rata-rata):
1 2.871 2.828 2.835 => 2.84446732686
2 2.144 2.097 2.157 => 2.13275338734
4 2.129 2.297 2.247 => 2.22436720645
8 2.151 2.174 2.170 => 2.16477771575
16 2.164 2.159 2.167 => 2.16328197911
32 2.102 2.117 2.154 => 2.12437970598
64 2.145 2.133 2.126 => 2.13462250728
128 2.135 2.122 2.137 => 2.13145065221
256 2.136 2.124 2.140 => 2.13336283943
512 2.140 2.188 2.179 => 2.1688431668
1024 2.162 2.158 2.167 => 2.16208440826
2048 2.207 2.176 2.213 => 2.19829998424
4096 2.180 2.196 2.202 => 2.19291917834
8192 2.173 2.215 2.188 => 2.19207065277
16384 2.258 2.232 2.249 => 2.24609975704
32768 2.262 2.251 2.274 => 2.26239771771
65536 2.298 2.264 2.246 => 2.26917420394
131072 2.285 2.266 2.313 => 2.28767871168
262144 2.351 2.333 2.366 => 2.35030805124
524288 2.932 2.816 2.834 => 2.86047313113
1048576 3.312 3.343 3.326 => 3.32721167007
2097152 3.461 3.451 3.547 => 3.48622758473
4194304 3.479 3.503 3.547 => 3.50964316455
8388608 3.733 3.496 3.532 => 3.58716466865
16777216 3.583 3.522 3.569 => 3.55790996695
33554432 3.550 3.556 3.512 => 3.53952594744
Jadi dari sekitar 2,8 detik untuk satu elemen (berulang) turun menjadi sekitar 2,2 detik untuk 2, 4, 8, 16, ... elemen yang berbeda dan tetap di sekitar 2,2 detik hingga ratusan ribu. Saya pikir ini menggunakan cache L2 saya (4 × 256 KB, saya memiliki i7-6700 ).
Kemudian selama beberapa langkah, waktunya naik menjadi 3,5 detik. Saya rasa ini menggunakan campuran cache L2 saya dan cache L3 saya (8 MB) hingga "habis" juga.
Pada akhirnya itu tetap sekitar 3,5 detik, saya kira karena cache saya tidak lagi membantu dengan elemen yang berulang.