Saya ingin tahu mengapa Raku melakukan manipulasi array multidimensi yang sangat buruk. Saya telah membuat tes cepat menginisialisasi matriks 2 dimensi dalam Python, C # dan Raku dan waktu yang berlalu sangat tinggi untuk nanti.
Untuk Raku
my @grid[4000;4000] = [[0 xx 4000] xx 4000];
# Elapsed time 42 seconds !!
Untuk Python
table= [ [ 0 for i in range(4000) ] for j in range(4000) ]
# Elapsed time 0.51 seconds
C #
int [,]matrix = new int[4000,4000];
//Just for mimic same behaviour
for(int i=0;i<4000;i++)
for(int j=0;j<4000;j++)
matrix[i,j] = 0;
# Elapsed time 0.096 seconds
Apakah saya salah? Sepertinya terlalu banyak perbedaan.
performance
raku
Javi
sumber
sumber
@grid[4000;4000]
) kode python tidak menggunakan array berbentuk dan dari Anda mencoba yang sama di Raku Anda mendapatkan waktu yang jauh lebih baik kembali:my @grid = [[0 xx 4000] xx 4000];
Itu berarti Anda harus mengakses dengan@grid[0][0]
tidak@grid[0;0]
. Saya pikir ini sebagian besar karena array berbentuk masih dalam proses.@grid[1000;1000] = [[0 xx 1000]xx1000]
butuh 12 detik.@grid = [[0 xx 1000]xx1000]
mengambil 0,6 jadi ... ya. Saya akan menghindari array berbentuk.my @grid = [[$++ xx 100] xx 100]; say @grid[0;1]; say @grid[1;1]
mengembalikan masingJawaban:
Perbandingan langsung awal
Saya akan mulai dengan kode yang jauh lebih selaras dengan kode Python Anda daripada terjemahan Anda sendiri. Saya pikir kode Raku yang paling langsung setara dengan Python Anda adalah:
Kode ini menyatakan pengidentifikasi sigil-free 1 . Itu:
Tetes "membentuk" (
[4000;4000]
dalammy @table[4000;4000]
). Saya menjatuhkannya karena kode Python Anda tidak melakukannya. Membentuk memberi keuntungan tetapi memiliki implikasi kinerja. 2Menggunakan ikatan bukan penugasan . Saya beralih ke pengikatan karena kode Python Anda melakukan pengikatan, bukan penugasan. (Python tidak membedakan antara keduanya.) Sementara pendekatan penugasan Raku membawa keuntungan mendasar yang layak dimiliki untuk kode umum, ia memiliki implikasi kinerja. 3
Kode ini saya mulai dengan jawaban saya masih lambat.
Pertama, kode Raku, dijalankan melalui kompilator Rakudo dari Desember 2018, sekitar 5 kali lebih lambat dari kode Python Anda, menggunakan juru bahasa Python dari Juni 2019, pada perangkat keras yang sama. 3
Kedua, baik kode Raku dan kode Python lambat, misalnya dibandingkan dengan kode C # Anda. Kita bisa melakukan yang lebih baik ...
Alternatif idiomatik yang seribu kali lebih cepat
Kode berikut layak dipertimbangkan:
Meskipun kode ini sesuai dengan 10 miliar elemen array nosional daripada hanya 16 juta elemen satu dalam kode Python dan C # Anda, waktu wallclock untuk menjalankannya kurang dari setengah dari kode Python, dan hanya 5 kali lebih lambat daripada C # kode. Itu menunjukkan Rakudo menjalankan kode Raku lebih dari seribu kali lebih cepat dari kode Python yang setara, dan seratus kali lebih cepat dari kode C #.
Kode Raku tampaknya jauh lebih cepat karena tabel sedang diinisialisasi malas dengan menggunakan
xx Inf
. 4 Satu-satunya pekerjaan signifikan yang dilakukan untuk menjalankansay
saluran. Hal ini menyebabkan pembuatan 100.000 array dimensi pertama, dan kemudian mengisi hanya array dimensi kedua 100.000 dengan 100.000 elemen, sehinggasay
dapat menampilkan yang0
ditahan di elemen terakhir array itu.Ada Lebih Dari Satu Cara Untuk Melakukannya
Satu masalah yang mendasari pertanyaan Anda adalah selalu ada lebih dari satu cara untuk melakukannya. 5 Jika Anda menemukan kinerja yang buruk untuk kode yang kecepatannya kritis, mengkodekannya secara berbeda, seperti yang telah saya lakukan, dapat membuat perbedaan dramatis. 6
(Pilihan lain yang sangat bagus adalah mengajukan pertanyaan SO ...)
Masa depan
Raku hati-hati dirancang untuk menjadi sangat optimiz mampu , yaitu mampu untuk satu hari run lebih cepat diberikan pekerjaan compiler yang cukup atas tahun-tahun mendatang , dari, katakanlah, Perl 5 atau Python 3 kaleng, secara teori, pernah menjalankan, kecuali mereka pergi melalui tanah- sebuah desain ulang dan tahun kerja kompiler yang sesuai.
Analogi yang agak baik adalah apa yang terjadi dengan kinerja Java selama 25 tahun terakhir. Rakudo / NQP / MoarVM sekitar setengah jalan melalui proses jatuh tempo yang telah ditumpuk oleh Java stack.
Catatan kaki
1 Saya bisa menulis
my $table := ...
. Tetapi deklarasi formulirmy \foo ...
menghilangkan pertimbangan sigil dan memungkinkan penggunaan=
daripada:=
yang diperlukan dengan pengidentifikasi sigil. (Sebagai bonus, "memotong sigil" menghasilkan pengenal sigil gratis, yang biasa bagi para pembuat kode dalam banyak bahasa yang tidak menggunakan sigil yang tentu saja termasuk Python dan C #.)2 Membentuk suatu hari dapat menghasilkan operasi array yang lebih cepat untuk beberapa kode. Sementara itu, seperti yang disebutkan dalam komentar pada pertanyaan Anda, saat ini jelas sebaliknya, secara signifikan memperlambatnya. Saya membayangkan itu sebagian besar karena setiap akses array secara naif diperiksa secara dinamis pada saat ini, perlahan-lahan semuanya turun, dan juga tidak ada upaya untuk menggunakan ukuran tetap untuk membantu mempercepat segalanya. Selain itu, ketika saya mencoba menemukan solusi cepat untuk kode Anda, saya gagal menemukan satu menggunakan array ukuran tetap karena banyak operasi pada array ukuran tetap sedang tidak diterapkan. Sekali lagi, ini diharapkan akan dilaksanakan suatu hari tetapi mungkin belum menjadi titik rasa sakit yang cukup bagi siapa pun untuk bekerja menerapkannya sampai saat ini.
3 Pada saat penulisan ini, TIO menggunakan Python 3.7.4, dari Juni 2019, dan Rakudo v2018.12, dari Desember 2018. Kinerja Rakudo saat ini membaik secara signifikan lebih cepat dari pada waktu yang ditentukan oleh penerjemah resmi Python 3, jadi saya ingin mengharapkan celah antara Rakudo terbaru dan Python terbaru, ketika Rakudo lebih lambat, secara signifikan lebih sempit daripada yang dinyatakan dalam jawaban ini. Secara khusus, pekerjaan saat ini secara signifikan meningkatkan kinerja penugasan.
4
xx
standar untuk pemrosesan malas tetapi beberapa ekspresi memaksa evaluasi bersemangat karena baik semantik bahasa atau keterbatasan kompilator saat ini. Pada tahun v2018.12 Rakudo, untuk ekspresi bentuk[ [ foo xx bar ] xx baz ]
tetap malas dan tidak dipaksa untuk mengevaluasi dengan bersemangat, keduanyabar
danbaz
harusInf
. Sebaliknya,my \table = [0 xx 100_000 for ^100_000]
malas tanpa menggunakanInf
. (Kode terakhir sebenarnya menyimpan 100.000Seq
detik di dimensi pertama daripada 100.000Array
detik -say WHAT table[0]
menampilkanSeq
daripadaArray
- tetapi sebagian besar kode tidak akan dapat menemukan perbedaannya -say table[99_999;99_999]
masih akan ditampilkan0
.)5 Beberapa orang berpikir bahwa itu adalah kelemahan untuk menerima bahwa ada lebih dari satu cara untuk memikirkan dan memberi kode solusi untuk masalah yang diberikan. Pada kenyataannya itu adalah kekuatan setidaknya dalam tiga hal. Pertama, secara umum, setiap masalah non-sepele yang diberikan dapat diselesaikan oleh banyak algoritma berbeda dengan perbedaan dramatis dalam profil kinerja. Jawaban ini mencakup pendekatan yang sudah tersedia dengan Rakudo berusia satu tahun yang akan lebih dari seribu kali lebih cepat daripada Python dalam praktiknya dalam beberapa skenario. Kedua, bahasa multi-paradigma yang sengaja fleksibel dan seperti Raku memungkinkan seorang pembuat kode (atau tim pembuat kode) untuk mengekspresikan solusi yang mereka anggap elegan dan dapat dipertahankan, atau yang baru saja menyelesaikan pekerjaan, berdasarkan apa yang merekaberpikir adalah yang terbaik, bukan apa yang dipaksakan oleh bahasa Ketiga, kinerja Rakudo sebagai kompiler pengoptimal saat ini sangat bervariasi. Untungnya ia memiliki profiler 6 yang hebat , sehingga orang dapat melihat di mana bottleneck berada, dan fleksibilitas yang besar, sehingga orang dapat mencoba kode alternatif dan ini dapat menghasilkan kode yang jauh lebih cepat.
6 Ketika kinerja penting, atau jika Anda menyelidiki masalah kinerja, lihat halaman Raku doc tentang kinerja ; halaman ini mencakup berbagai opsi termasuk penggunaan profiler Rakudo.
sumber