Kode seperti ini sering terjadi:
l = []
while foo:
#baz
l.append(bar)
#qux
Ini sangat lambat jika Anda akan menambahkan ribuan elemen ke daftar Anda, karena daftar harus terus diubah ukurannya agar sesuai dengan elemen baru.
Di Jawa, Anda bisa membuat ArrayList dengan kapasitas awal. Jika Anda tahu seberapa besar daftar Anda, ini akan jauh lebih efisien.
Saya mengerti bahwa kode seperti ini sering dapat difaktorkan ulang ke dalam daftar pemahaman. Namun, jika for / while loop sangat rumit, ini tidak mungkin. Apakah ada yang setara dengan kami programmer Python?
python
list
dictionary
initialization
Claudiu
sumber
sumber
Jawaban:
Hasil . (mengevaluasi setiap fungsi 144 kali dan rata-rata durasinya)
Kesimpulan . Itu hampir tidak penting.
Optimalisasi prematur adalah akar dari semua kejahatan.
sumber
Daftar python tidak memiliki pra-alokasi bawaan. Jika Anda benar-benar perlu membuat daftar, dan perlu menghindari biaya tambahan untuk menambahkan (dan Anda harus memverifikasi bahwa Anda melakukannya), Anda dapat melakukan ini:
Mungkin Anda bisa menghindari daftar dengan menggunakan generator sebagai gantinya:
Dengan cara ini, daftar tidak semua disimpan dalam memori sama sekali, hanya dihasilkan sesuai kebutuhan.
sumber
Versi singkat: gunakan
untuk pra-mengalokasikan daftar (yaitu, untuk dapat mengatasi 'ukuran' elemen daftar daripada secara bertahap membentuk daftar dengan menambahkan). Operasi ini SANGAT cepat, bahkan pada daftar besar. Mengalokasikan objek baru yang nantinya akan ditugaskan ke elemen daftar akan memakan waktu JAUH lebih lama dan akan menjadi hambatan dalam program Anda, kinerja-bijaksana.
Versi panjang:
Saya pikir waktu inisialisasi harus diperhitungkan. Karena dalam python semuanya adalah referensi, tidak masalah apakah Anda mengatur setiap elemen menjadi Tidak Ada atau string - baik itu hanya referensi. Meskipun akan lebih lama jika Anda ingin membuat objek baru untuk setiap elemen untuk referensi.
Untuk Python 3.2:
Evaluasi:
Seperti yang Anda lihat, hanya membuat daftar besar referensi ke objek None yang sama membutuhkan waktu sangat sedikit.
Membebani atau memperpanjang membutuhkan waktu lebih lama (saya tidak melakukan rata-rata apa pun, tetapi setelah menjalankan ini beberapa kali saya dapat memberi tahu Anda bahwa perluasan dan penambahan memakan waktu yang hampir bersamaan).
Mengalokasikan objek baru untuk setiap elemen - itulah yang paling memakan waktu. Dan jawaban S.Lott melakukan itu - memformat string baru setiap kali. Yang tidak sepenuhnya diperlukan - jika Anda ingin pra-mengalokasikan beberapa ruang, cukup buat daftar Tidak Ada, lalu tetapkan data ke daftar elemen sesuka hati. Apa pun cara yang dibutuhkan lebih banyak waktu untuk menghasilkan data daripada menambahkan / memperpanjang daftar, apakah Anda menghasilkannya saat membuat daftar, atau setelah itu. Tetapi jika Anda menginginkan daftar yang jarang penduduknya, maka memulai dengan daftar Tidak Ada jelas lebih cepat.
sumber
[]*
pendekatanCara Pythonic untuk ini adalah:
atau nilai default apa pun yang ingin Anda siapkan, mis
[EDIT: Caveat Emptor The
[Beer()] * 99
sintaks menciptakan satuBeer
dan kemudian Mempopulai sebuah array dengan referensi 99 untuk satu contoh yang sama]Pendekatan default Python bisa sangat efisien, meskipun efisiensi itu meluruh ketika Anda meningkatkan jumlah elemen.
Membandingkan
dengan
Pada Windows 7 i7 saya, Python 64-bit memberi
Sementara C ++ memberi (dibangun dengan MSVC, 64-bit, Pengoptimalan diaktifkan)
C ++ debug build menghasilkan:
Intinya di sini adalah bahwa dengan Python Anda dapat mencapai peningkatan kinerja 7-8%, dan jika Anda berpikir Anda sedang menulis aplikasi berkinerja tinggi (atau jika Anda sedang menulis sesuatu yang digunakan dalam layanan web atau sesuatu) maka itu tidak bisa diendus, tetapi Anda mungkin perlu memikirkan kembali pilihan bahasa Anda.
Juga, kode Python di sini bukan kode Python. Beralih ke kode Pythonesque yang sesungguhnya di sini memberikan kinerja yang lebih baik:
Pemberian yang mana
(dalam doGenerator 32-bit lebih baik daripada doAllocate).
Di sini kesenjangan antara doAppend dan doAllocate secara signifikan lebih besar.
Jelas, perbedaan di sini benar-benar hanya berlaku jika Anda melakukan ini lebih dari beberapa kali atau jika Anda melakukan ini pada sistem yang sarat dengan beban di mana angka-angka itu akan diperkecil oleh urutan besarnya, atau jika Anda berurusan dengan daftar jauh lebih besar.
Intinya di sini: Lakukan dengan cara pythonic untuk kinerja terbaik.
Tetapi jika Anda khawatir tentang kinerja tingkat tinggi yang umum, Python adalah bahasa yang salah. Masalah yang paling mendasar adalah bahwa panggilan fungsi Python secara tradisional lebih lambat hingga 300x daripada bahasa lain karena fitur Python seperti dekorator dll ( https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ).
sumber
timeit
timeit
, yang harus Anda gunakan saat menghitung kode Python Anda; Saya tidak berbicara tentang C ++, jelas.bottles = [Beer()] * 99
tidak membuat 99 objek Bir. Sebaliknya, buat satu objek Bir dengan 99 referensi untuk itu. Jika Anda akan mengubahnya, semua elemen dalam daftar akan dimutasi, sebab(bottles[i] is bootles[j]) == True
untuk setiapi != j. 0<= i, j <= 99
.Seperti yang disebutkan orang lain, cara paling sederhana untuk melakukan pra-seeding daftar dengan
NoneType
objek.Yang sedang berkata, Anda harus memahami cara daftar Python benar-benar berfungsi sebelum memutuskan ini diperlukan. Dalam implementasi daftar CPython, array yang mendasari selalu dibuat dengan ruang overhead, dalam ukuran yang semakin besar
( 4, 8, 16, 25, 35, 46, 58, 72, 88, 106, 126, 148, 173, 201, 233, 269, 309, 354, 405, 462, 526, 598, 679, 771, 874, 990, 1120, etc)
, sehingga mengubah ukuran daftar tidak terjadi hampir begitu sering.Karena perilaku ini, sebagian besar
list.append()
fungsi adalahO(1)
kompleksitas untuk ditambahkan, hanya memiliki peningkatan kompleksitas ketika melewati salah satu dari batas-batas ini, pada titik mana kompleksitas akan terjadiO(n)
. Perilaku ini yang mengarah pada peningkatan minimal dalam waktu eksekusi dalam jawaban S. Lott.Sumber: http://www.laurentluce.com/posts/python-list-implementation/
sumber
saya menjalankan kode @ s.lott dan menghasilkan peningkatan perf 10% yang sama dengan pra-alokasi. mencoba ide @ jeremy menggunakan generator dan mampu melihat perf gen lebih baik daripada doAllocate. Untuk proyek saya, 10% peningkatan penting, jadi terima kasih kepada semua orang karena ini membantu banyak orang.
sumber
Kekhawatiran tentang pra-alokasi dalam Python muncul jika Anda bekerja dengan numpy, yang memiliki lebih banyak array mirip-C. Dalam hal ini, kekhawatiran pra-alokasi adalah tentang bentuk data dan nilai default.
Pertimbangkan numpy jika Anda melakukan perhitungan numerik pada daftar besar dan menginginkan kinerja.
sumber
Untuk beberapa aplikasi, kamus mungkin sesuai dengan yang Anda cari. Misalnya, dalam metode find_totient, saya merasa lebih nyaman menggunakan kamus karena saya tidak memiliki indeks nol.
Masalah ini juga dapat diselesaikan dengan daftar yang sudah dialokasikan:
Saya merasa bahwa ini tidak elegan dan rentan terhadap bug karena saya menyimpan Tidak ada yang bisa mengeluarkan pengecualian jika saya tidak sengaja menggunakannya salah, dan karena saya perlu berpikir tentang kasus tepi bahwa peta memungkinkan saya menghindari.
Memang benar kamus tidak akan seefisien, tetapi seperti yang telah dikomentari orang lain, perbedaan kecil dalam kecepatan tidak selalu berarti bahaya pemeliharaan yang signifikan .
sumber
Dari apa yang saya mengerti, daftar python sudah sangat mirip dengan ArrayLists. Tetapi jika Anda ingin mengubah parameter tersebut, saya menemukan posting ini di internet yang mungkin menarik (pada dasarnya, buat saja
ScalableList
ekstensi Anda sendiri ):http://mail.python.org/pipermail/python-list/2000-May/035082.html
sumber