ทำไม Raku ถึงทำงานได้แย่มากกับอาเรย์หลายมิติ


10

ฉันสงสัยว่าทำไม Raku ถึงทำงานได้แย่มากในการจัดการกับอาร์เรย์หลายมิติ ฉันได้ทำการทดสอบอย่างรวดเร็วเพื่อเริ่มต้นเมทริกซ์ 2 มิติใน Python, C # และ Raku และเวลาที่ผ่านไปนั้นสูงอย่างน่าประหลาดใจในภายหลัง

สำหรับ Raku

my @grid[4000;4000] = [[0 xx 4000] xx 4000];
# Elapsed time 42 seconds !!

สำหรับงูหลาม

table= [ [ 0 for i in range(4000) ] for j in range(4000) ]
# Elapsed time 0.51 seconds

ค#

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

ฉันทำผิดหรือเปล่า? ดูเหมือนความแตกต่างทางมากเกินไป


5
มันช้าสำหรับอาร์เรย์หลายมิติที่มีรูปร่าง (EG หนึ่งที่คุณกำหนดไว้@grid[4000;4000]) รหัสหลามไม่ได้ใช้อาร์เรย์ที่มีรูปร่างและคุณลองแบบเดียวกันใน Raku คุณจะได้เวลาที่ดีกว่า: my @grid = [[0 xx 4000] xx 4000]; มันหมายความว่าคุณต้องเข้าถึงด้วยไม่@grid[0][0] @grid[0;0]ฉันคิดว่านี่เป็นส่วนใหญ่เพราะอาร์เรย์ที่มีรูปร่างยังคงทำงานอยู่
Scimon Proctor

1
บนเครื่องของฉัน@grid[1000;1000] = [[0 xx 1000]xx1000]ใช้เวลา 12 วินาที @grid = [[0 xx 1000]xx1000]เอา 0.6 ดังนั้น ... ใช่ ฉันจะหลีกเลี่ยงอาร์เรย์ที่มีรูปร่าง
Scimon Proctor

5
@Scimon คุณยังสามารถใช้ [;] accessor สำหรับอาร์เรย์ที่ไม่มีรูปร่างได้ my @grid = [[$++ xx 100] xx 100]; say @grid[0;1]; say @grid[1;1]ส่งคืน 1 และ 101 ตามลำดับ
user0721090601

! น่ากลัว ทำให้สิ่งต่าง ๆ ง่ายขึ้น
Scimon Proctor

2
อาร์เรย์หลายมิติที่มีรูปทรงยังไม่ได้รับการปรับปรุงความเหมาะสม แต่พื้นที่อื่น ๆ ของ Rakudo ได้รับ
Elizabeth Mattijsen

คำตอบ:


13

การเปรียบเทียบโดยตรงครั้งแรก

ฉันจะเริ่มต้นด้วยรหัสที่สอดคล้องกันมากกับรหัส Python ของคุณมากกว่าการแปลของคุณเอง ฉันคิดว่ารหัส Raku ที่เทียบเท่าโดยตรงกับ Python ของคุณมากที่สุดคือ:

my \table = [ [ 0 for ^4000 ] for ^4000 ];
say table[3999;3999]; # 0

รหัสนี้ประกาศตัวระบุเครื่องหมายฟรี1 มัน:

  • วาง "รูปร่าง" ( [4000;4000]ในmy @table[4000;4000]) ฉันทำผิดเพราะรหัส Python ของคุณไม่ได้ทำ การสร้างฟาโรห์ให้ประโยชน์ แต่มีผลกระทบด้านประสิทธิภาพ 2

  • การใช้งานที่มีผลผูกพันแทนการที่ได้รับมอบหมาย ฉันเปลี่ยนมาใช้การผูกเพราะรหัส Python ของคุณกำลังทำการผูกไม่ใช่การมอบหมาย (Python ไม่ได้แยกความแตกต่างระหว่างทั้งสอง) ในขณะที่วิธีการมอบหมายของ Raku นำข้อดีพื้นฐานที่ควรค่าแก่การใช้รหัสทั่วไปมาใช้ 3


รหัสนี้ฉันได้เริ่มตอบด้วยยังช้า

อันดับแรกรหัส Raku ทำงานผ่านคอมไพเลอร์ Rakudo ตั้งแต่เดือนธันวาคม 2018 ช้ากว่ารหัส Python ของคุณประมาณ 5 เท่าโดยใช้ Python interpreter ตั้งแต่เดือนมิถุนายน 2019 บนฮาร์ดแวร์เดียวกัน 3

ประการที่สองทั้งรหัส Raku และรหัส Python ช้าเช่นเปรียบเทียบกับรหัส C # ของคุณ เราทำได้ดีกว่า ...

ทางเลือกที่ใช้สำนวนที่เร็วกว่าพันเท่า

รหัสต่อไปนี้มีมูลค่าการพิจารณา:

my \table = [ [ 0 xx Inf ] xx Inf ];
say table[ 100_000; 100_000 ]; # 0

แม้จะมีรหัสนี้สอดคล้องกับอาร์เรย์องค์ประกอบหนึ่งล้านล้านไม่ใช่มากกว่าหนึ่งล้านองค์ประกอบใน Python และรหัส C # ของคุณ แต่เวลา wallclock สำหรับการทำงานนั้นน้อยกว่าครึ่งหนึ่งของรหัส Python และช้ากว่า C # เพียง 5 เท่า รหัส. นั่นแสดงให้เห็นว่า Rakudo กำลังเรียกใช้รหัส Raku มากกว่าหนึ่งพันเท่าเร็วเท่ากับรหัส Python ที่เทียบเท่ากันและเร็วเป็นร้อยเท่าของรหัส C #

รหัส Raku ดูเหมือนจะมากได้เร็วขึ้นเนื่องจากตารางจะถูกเริ่มต้นได้อย่างเฉื่อยชาxx Infโดยใช้ 4งานที่สำคัญเพียงอย่างเดียวเกิดขึ้นกับการเรียกใช้sayบรรทัด สิ่งนี้ทำให้เกิดการสร้างอาร์เรย์มิติแรก 100,000 ชุดจากนั้นจึงเติมอาร์เรย์มิติที่สองที่ 100,000 ด้วยองค์ประกอบ 100,000 เพื่อให้sayสามารถแสดงการ0จัดเก็บในองค์ประกอบสุดท้ายของอาร์เรย์นั้น

มีมากกว่าหนึ่งวิธีที่จะทำ

ปัญหาหนึ่งที่อยู่ภายใต้คำถามของคุณคือมีมากกว่าหนึ่งวิธีที่จะทำ 5หากคุณพบกับประสิทธิภาพที่ไม่ดีสำหรับโค้ดที่ความเร็วมีความสำคัญการเขียนโค้ดต่างกันอย่างที่ฉันได้ทำอาจสร้างความแตกต่างได้อย่างมาก 6

(อีกตัวเลือกที่ดีจริงๆคือถามคำถาม SO ... )

อนาคต

Raku ได้รับการออกแบบอย่างระมัดระวังเพื่อจะสูงการเพิ่มประสิทธิภาพสามารถคือสามารถที่จะวันหนึ่งวิ่งให้เร็วขึ้นมากการทำงานของคอมไพเลอร์ที่เพียงพอในช่วงปีที่ผ่านมากว่าการพูด, Perl 5 หรืองูหลาม 3 สามารถในทางทฤษฎีเรียกเคยจนกว่าพวกเขาจะไปผ่านภาคพื้นดิน ออกแบบและคอมไพเลอร์ที่สอดคล้องกันเป็นเวลาหลายปี

การเปรียบเทียบที่ค่อนข้างโอเคคือสิ่งที่เกิดขึ้นกับประสิทธิภาพของ Java ในช่วง 25 ปีที่ผ่านมา Rakudo / NQP / MoarVM ประมาณครึ่งทางผ่านกระบวนการสุกที่สแต็ก Java ผ่านไปแล้ว

เชิงอรรถ

1ฉันสามารถเขียนmy $table := ...ได้ แต่การประกาศในแบบฟอร์มmy \foo ...กำจัดการพิจารณาของ sigils และอนุญาตให้ใช้=มากกว่า:=ที่จะต้องใช้กับตัวบ่งชี้ sigil'd (ในฐานะโบนัสการ "ตัดออก sigil" ให้ผลลัพธ์เป็นตัวบ่งชี้ที่ปราศจาก sigil คุ้นเคยกับ coders ในหลายภาษาที่ไม่ได้ใช้ sigils ซึ่งแน่นอนรวมถึง Python และ C #)

2 การปรับรูปแบบในวันหนึ่งอาจส่งผลให้การดำเนินการของอาเรย์เร็วขึ้นสำหรับบางโค้ด ในระหว่างนี้ดังที่ได้กล่าวไว้ในความคิดเห็นเกี่ยวกับคำถามของคุณขณะนี้มันตรงกันข้ามอย่างชัดเจนทำให้ช้าลงอย่างมีนัยสำคัญ ฉันคิดว่าส่วนใหญ่เพราะทุกการเข้าถึงอาร์เรย์จะถูกอย่างไร้เดียงสาแบบไดนามิกขอบเขตการตรวจสอบในขณะนี้ทุกอย่างช้าลงและยังได้รับความพยายามที่จะใช้ขนาดคงที่ไปสู่สิ่งที่ช่วยเพิ่มความเร็วในไม่มี นอกจากนี้เมื่อฉันพยายามหาวิธีแก้ปัญหาที่รวดเร็วสำหรับโค้ดของคุณฉันไม่สามารถหาอันที่ใช้อาร์เรย์ขนาดคงที่เนื่องจากการดำเนินการหลายอย่างในอาร์เรย์ขนาดคงที่ซึ่งยังไม่มีการใช้งานในปัจจุบัน หวังว่าสิ่งเหล่านี้จะได้รับการดำเนินการในหนึ่งวัน แต่คาดว่าจะไม่เป็นจุดเจ็บปวดที่เพียงพอสำหรับทุกคนในการดำเนินการให้เป็นปัจจุบัน

3ในขณะที่เขียนสิ่งนี้TIOใช้ Python 3.7.4 ตั้งแต่เดือนมิถุนายน 2019 และ Rakudo v2018.12 ตั้งแต่เดือนธันวาคม 2561 ในขณะนี้ประสิทธิภาพของ Rakudo กำลังพัฒนาขึ้นอย่างรวดเร็วกว่าล่าม Python 3 อย่างเป็นทางการดังนั้นฉันจะ คาดว่าช่องว่างระหว่าง Rakudo ล่าสุดและ Python ล่าสุดเมื่อ Rakudo ช้าลงจะแคบลงกว่าที่ระบุไว้ในคำตอบนี้ โดยเฉพาะอย่างยิ่งงานปัจจุบันมีการปรับปรุงประสิทธิภาพของการมอบหมายอย่างมีนัยสำคัญ

4 xxค่าเริ่มต้นสำหรับการประมวลผลที่ขี้เกียจ แต่นิพจน์บางอย่างบังคับให้มีการประเมินผลที่กระตือรือร้นเนื่องจากความหมายของภาษาหรือข้อ จำกัด ของคอมไพเลอร์ในปัจจุบัน ใน v2018.12 Rakudo ปีเก่าสำหรับการแสดงออกของรูปแบบที่[ [ foo xx bar ] xx baz ]จะยังคงขี้เกียจและไม่ได้ถูกบังคับให้ประเมินกระหายทั้งสอง barและจะต้องเป็นbaz Infในทางตรงกันข้ามคือขี้เกียจที่มีการใช้ไม่มีmy \table = [0 xx 100_000 for ^100_000] Inf(รหัสหลังคือการจัดเก็บ 100,000 Seqs ในมิติแรกมากกว่า 100,000 Arrays - say WHAT table[0]แสดงSeqมากกว่าArray- แต่รหัสส่วนใหญ่จะไม่สามารถเห็นความแตกต่าง - say table[99_999;99_999]จะยังคงแสดง0)

5ชาวบ้านบางคนคิดว่ามันเป็นจุดอ่อนที่จะยอมรับว่ามีมากกว่าหนึ่งวิธีในการคิดและการแก้ปัญหาของการแก้ปัญหา ในความเป็นจริงมันมีความแข็งแกร่งอย่างน้อยสามประการ ประการแรกโดยทั่วไปปัญหาที่ไม่ได้รับใด ๆ สามารถแก้ไขได้ด้วยอัลกอริทึมที่แตกต่างกันจำนวนมากที่มีความแตกต่างอย่างมากในโปรไฟล์ประสิทธิภาพ คำตอบนี้รวมถึงวิธีการที่มีอยู่แล้วใน Rakudo ซึ่งมีอายุหนึ่งปีซึ่งจะเร็วกว่าการใช้ Python มากกว่าพันเท่าในบางสถานการณ์ ประการที่สองภาษาที่มีความยืดหยุ่นและมีกระบวนทัศน์ที่หลากหลายเช่น Raku อนุญาตให้ coder (หรือทีมงานของผู้เขียนโค้ด) แสดงวิธีแก้ปัญหาที่พวกเขาคิดว่าสง่างามและบำรุงรักษาหรือที่เพิ่งทำงานเสร็จตามสิ่งที่พวกเขาทำคิดว่าดีที่สุดไม่ใช่สิ่งที่ภาษากำหนด ประการที่สามประสิทธิภาพของ Rakudo ในฐานะที่เป็นคอมไพเลอร์ที่ปรับให้เหมาะสมที่สุดคือตัวแปรที่สะดุดตาในปัจจุบัน โชคดีที่มันมี profiler 6ที่ยอดเยี่ยมดังนั้นใคร ๆ ก็สามารถเห็นได้ว่าคอขวดอยู่ตรงไหนและมีความยืดหยุ่นที่ดีเยี่ยมดังนั้นเราสามารถลองเข้ารหัสแบบอื่นได้

6เมื่อเรื่องประสิทธิภาพการทำงานหรือถ้าคุณกำลังตรวจสอบปัญหาการปฏิบัติงานให้คำปรึกษาหน้า doc Raku ต่อประสิทธิภาพการทำงาน ; หน้านี้ครอบคลุมตัวเลือกมากมายรวมถึงการใช้งาน Rakudo Profiler

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.