Ini adalah perintah perl_performance yang dapat dijalankan di penyedia hosting gratis OnWorks menggunakan salah satu dari beberapa workstation online gratis kami seperti Ubuntu Online, Fedora Online, emulator online Windows atau emulator online MAC OS
PROGRAM:
NAMA
makepp_perl_performance -- Cara membuat Perl lebih cepat
DESKRIPSI
Keuntungan penyetelan terbesar biasanya akan datang dari peningkatan algoritmik. Tapi sementara ini
bisa sulit ditemukan, ada juga banyak hal yang dapat Anda lakukan secara mekanis.
Makepp adalah program tugas berat yang besar, di mana kecepatan adalah suatu keharusan. Banyak usaha telah dilakukan
dalam mengoptimalkannya. Ini mendokumentasikan beberapa hal umum yang kami temukan. Saat ini
tes konkret yang mengarah ke hasil ini sebagian besar telah dibuang, tetapi saya berencana untuk
secara bertahap menambahkannya.
Jika Anda mencari cara untuk mempercepat makepp (di luar pemrograman Perl yang Anda masukkan ke dalam
makefiles), lihat makepp_speedup. Halaman ini sepenuhnya independen dari makepp, hanya
dimaksudkan untuk membuat hasil kami tersedia untuk komunitas Perl. Beberapa tindakan tersebut adalah
akal sehat, tetapi Anda terkadang melupakannya. Orang lain perlu mengukur untuk mempercayainya, jadi:
Ukuran, tidak kira
Profil program Anda
Makepp dilengkapi dengan modul profiler.pm dalam repositori cvs-nya. Ini pertama kali dijalankan sebagai
program pada salinan (!) dari kode Anda, yang instrumennya. Kemudian Anda menjalankan salinan Anda dan
dapatkan statistik yang dapat dikonfigurasi per interval dan total akhir paling sering
memanggil fungsi dan paling banyak menghabiskan waktu dalam fungsi (dikurangi subpanggilan). Keduanya
disediakan secara mutlak dan dalam pasangan penelepon-pemanggil. (Dokumentasi di dalam.)
Ini memberi tahu Anda fungsi mana yang paling menjanjikan untuk disetel. Juga
memberi Anda petunjuk di mana algoritme Anda mungkin salah, baik secara mengejutkan
fungsi mahal, atau melalui panggilan yang sangat sering.
Atur waktu solusi Anda
Salah satu dari
perl -Mstrict -MBenchmark -we 'my ; waktu ini -10, sub { }'
time perl -Mstrict -we 'my ; untuk( 0..999_999 ) { }'
ketika dijalankan pada berbagai varian kode yang dapat Anda pikirkan, dapat memberikan hasil yang mengejutkan.
Bahkan modifikasi kecil bisa sangat berarti. Berhati-hatilah untuk tidak "mengukur" kode yang dapat
dioptimalkan, karena Anda membuang hasilnya, atau karena itu tergantung pada
konstanta.
Bergantung pada sistem Anda, ini akan memberi tahu Anda dalam kb seberapa gemuk Perl:
perl -Mstrict -kita ' ; sistem "ps -ovsz $$"'
Di bawah ini kami hanya menampilkan kode dalam opsi "-e" sebagai satu baris.
Regexp
Gunakan regexp sederhana
Beberapa kecocokan dikombinasikan dengan "||" lebih cepat daripada yang besar dengan "|".
Gunakan regexp yang sudah dikompilasi
Alih-alih menginterpolasi string menjadi regexps (kecuali jika string tidak akan pernah berubah
dan Anda menggunakan pengubah "o"), kompilasi regexp terlebih dahulu dengan "qr//" dan interpolasi itu.
Menggunakan (?:...)
Jika Anda tidak menggunakan pengelompokan yang cocok, jangan buat Perl menyimpannya dengan "(...)".
Jangkar di awal string
Jangan membuat Perl melihat seluruh string Anda, jika Anda ingin kecocokan hanya di
awal.
Jangan berlabuh di akhir setelah serakah
Jika Anda memiliki "*" atau "+" yang akan cocok sampai akhir string, jangan letakkan "$" setelahnya
.
Gunakan tr///
Ini dua kali lebih cepat dari s/// ketika itu berlaku.
Fungsi
Hindari orientasi objek
Pencarian metode dinamis lebih lambat dalam bahasa apa pun, dan Perl, yang diketik secara longgar, dapat
jangan pernah melakukannya pada waktu kompilasi. Jangan menggunakannya, kecuali jika Anda membutuhkan manfaat dari
polimorfisme melalui pewarisan. Metode panggilan berikut diurutkan dari yang paling lambat
untuk tercepat:
$o->metode( ... ); # dicari di kelas $o dan @ISA
Kelas::metode( $o, ... ); # fungsi statis, tumpukan baru
Kelas::metode $o, ...; # fungsi statis, tumpukan baru, diperiksa pada waktu kompilasi
&Kelas::metode; # fungsi statis, gunakan kembali tumpukan
Bentuk terakhir ini selalu memungkinkan jika metode (atau fungsi normal) tidak membutuhkan argumen. Jika
itu memang membutuhkan argumen, hati-hati agar Anda tidak secara tidak sengaja memberikan opsional apa pun
yang! Jika Anda sering menggunakan formulir ini, yang terbaik adalah melacak minimum dan maksimum
jumlah argumen yang dapat diambil oleh setiap fungsi. Menggunakan kembali tumpukan dengan argumen tambahan adalah
tidak masalah, mereka akan diabaikan.
Jangan ubah tumpukan
Dosa berikut sering ditemukan bahkan di dokumen Perl:
$diri saya = shift;
Kecuali Anda memiliki alasan yang relevan untuk ini, gunakan ini:
saya( $diri, $x, $y, @z ) = @_;
Gunakan beberapa fungsi dan modul
Setiap fungsi (dan sayangnya termasuk konstanta) membutuhkan lebih dari 1 kb karena itu hanya
adanya. Dengan setiap modul membutuhkan yang lain, yang sebagian besar tidak Anda butuhkan, itu
dapat menambahkan. Jangan menarik modul besar, cukup ganti dua baris kode Perl dengan a
panggilan fungsi yang terlihat lebih elegan.
Jika Anda memiliki fungsi yang hanya dipanggil di satu tempat, dan keduanya digabungkan akan tetap
cukup singkat, gabungkan mereka dengan komentar yang tepat.
Jangan memiliki satu fungsi, panggil saja yang lain dengan argumen yang sama. Alias sebagai gantinya:
*alias = \&fungsi;
Panggilan grup untuk dicetak
Panggilan individu untuk mencetak, atau mencetak dengan argumen terpisah sangat mahal. Membangun
mengumpulkan string dalam memori dan mencetaknya sekaligus. Jika Anda dapat mengumpulkan lebih dari 3kb,
syswrite lebih efisien.
perl -MBenchmark -we 'timethis -10, sub { print STDERR $_ for 1 }' 5>/dev/null
perl -MBenchmark -we 'timethis -10, sub { print STDERR 1 }' 5>/dev/null
perl -MBenchmark -we 'timethis -10, sub { my $str = ""; $str .= $_ untuk 1; print STDERR $str }' 5>/dev/null
bermacam-macam
Hindari hash
Perl menjadi sangat lambat dengan banyak hash kecil. Jika Anda tidak membutuhkannya, gunakan sesuatu
lain. Orientasi objek bekerja dengan baik pada array, kecuali bahwa anggota
tidak dapat diakses dengan nama. Tetapi Anda dapat menggunakan konstanta numerik untuk memberi nama anggota.
Demi komparabilitas, kami menggunakan kunci numerik biasa di sini:
saya $i = 0; %a kami = peta +($i++, $_), "a"."j"; timethis -10, sub { $b = $a{int rand 10} }
@a kami = "a"."j"; timethis -10, sub { $b = $a[rand 10] }
saya $i = 0; %a saya = peta +($i++, $_), "a"."j"; timethis -10, sub { $b = $a{int rand 10} }
saya @a = "a"."j"; timethis -10, sub { $b = $a[rand 10] }
Gunakan kunci int untuk set ref
Saat Anda membutuhkan representasi referensi unik, misalnya untuk operasi set dengan hash, gunakan
bentuk bilangan bulat dari referensi tiga kali lebih cepat menggunakan default yang dicetak cantik
representasi string. Peringatan: varian Perl HP/UX 64bitall, setidaknya hingga
5.8.8 memiliki fungsi "int" buggy, di mana ini tidak bekerja dengan andal. Ada bentuk hex
masih sedikit lebih cepat dari string default. Sebenarnya ini bahkan bisa lebih cepat
daripada int string, tergantung pada versi atau mungkin konfigurasi Perl. Mulai dari
5.8.1 ada juga yang setara tetapi semoga dapat diandalkan Scalar::Util::refaddr
my @list = map { berkat { $_ => 1 }, "someclass" } 0..9; saya( %a, %b );
timethis -10, sub { $a{$_} = 1 untuk @daftar };
timethis -10, sub { $b{int()} = 1 untuk @daftar };
timethis -10, sub { $b{sprintf '%x', $_} = 1 untuk @daftar };
timethis -10, sub { $b{refaddr $_} = 1 untuk @daftar };
Ada juga sprintf '%p' yang seharusnya mengeluarkan pointer, tetapi tergantung yang mana
ekspresi mengarah ke referensi yang sama, Anda mendapatkan nilai yang berbeda, jadi itu tidak berguna.
Waspadalah terhadap string
Perl sangat buruk karena selalu menyalin string, bahkan jika Anda tidak akan pernah mengubahnya
mereka. Ini pemborosan CPU dan memori. Cobalah untuk menghindari itu sedapat mungkin.
Jika string adalah parameter fungsi dan fungsi memiliki panjang yang sederhana, jangan salin
string menjadi variabel "saya", akses dengan $_[0] dan dokumentasikan fungsinya dengan baik.
Di tempat lain, fitur aliasing "untuk (setiap)" dapat membantu. Atau gunakan saja referensi untuk
string, yang cepat untuk disalin. Jika Anda entah bagaimana memastikan bahwa string yang sama disimpan
hanya sekali, Anda dapat melakukan perbandingan numerik untuk kesetaraan.
Hindari operasi bit
Jika Anda memiliki pola bit yang terputus-putus, Anda dapat menambahkannya alih-alih mengubahnya. Pergeseran
dapat dilakukan perkalian atau pembagian bilangan bulat saya. Mempertahankan hanya yang terendah
bit dapat dicapai dengan modulo.
Anggota hash boolean yang terpisah lebih cepat daripada memasukkan semuanya ke dalam bilangan bulat dengan
operasi bit atau menjadi string dengan "vec".
Gunakan urutan operasi boolean
Jika Anda hanya peduli apakah ekspresi itu benar atau salah, periksa hal-hal murah, seperti
variabel boolean, pertama, dan fungsi panggilan terakhir.
Gunakan undef alih-alih 0
Dibutuhkan beberapa persen lebih sedikit memori, setidaknya sebagai nilai hash atau daftar. Kamu masih bisa
menanyakannya sebagai boolean.
%x saya; $x{$_} = 0 untuk 0_999; sistem "ps -ovsz $$"
%x saya; undef $x{$_} untuk 0_999; sistem "ps -ovsz $$"
saya @x = (0) x 999_999; sistem "ps -ovsz $$"
@x saya = (undef) x 999_999; sistem "ps -ovsz $$"
Pilih untuk atau peta
Ini jelas tidak setara. Tergantung pada penggunaan Anda (yaitu daftar dan
kompleksitas kode Anda), satu atau yang lain mungkin lebih cepat.
saya @l = 0;
untuk( 0..99_999 ) { peta $a = " $_ ", @l }
untuk( 0..99_999 ) { peta $a = " $_ ", 0..99 }
untuk( 0..99_999 ) { $a = " $_ " untuk @l }
untuk( 0_99 ) { $a = " $_ " untuk 999..0 }
Jangan alias $_
Meskipun nyaman, itu agak mahal, bahkan menyalin string yang masuk akal adalah
lebih cepat. Contoh terakhir dua kali lebih cepat dari "untuk" pertama.
$x saya = "abcdefg"; $b saya = 0;
for( "$x" ) { $b = 1 - $b if /g/ } # Salin hanya diperlukan jika memodifikasi.
untuk( $x ) { $b = 1 - $b jika /g/ }
lokal *_ = \$x; $b = 1 - $b jika /g/;
lokal $_ = $x; $b = 1 - $b jika /g/; # Salin lebih murah dari alias.
saya $y = $x; $b = 1 - $b jika $y =~ /g/;
Gunakan perl_performance online menggunakan layanan onworks.net