วิธีที่มีประสิทธิภาพมากที่สุดในการเขียนลูป 'for' ใน Matlab คืออะไร


12

ฉันได้อ่านแล้วว่าถ้าเช่นฉันมี double forloop ที่วิ่งอยู่เหนือ index ของเมทริกซ์จากนั้นการวางดัชนีการรันคอลัมน์ในลูปด้านนอกนั้นมีประสิทธิภาพมากกว่า ตัวอย่างเช่น:

a=zeros(1000);
for j=1:1000
 for i=1:1000
  a(i,j)=1;
 end
end

วิธีที่มีประสิทธิภาพมากที่สุดในการเขียนโค้ดคืออะไรถ้าฉันมีforลูปสามลูปขึ้นไป

ตัวอย่างเช่น:

a=zeros(100,100,100);
for j=1:100
 for i=1:100
  for k=1:100
   a(i,j,k)=1;
  end
 end
end

4
ForMATLAB วนซ้ำช้ามาก คุณควรหลีกเลี่ยงการวนซ้ำอย่างชัดเจนใน MATLAB ทุกครั้งที่ทำได้ แต่มักจะมีปัญหาสามารถแสดงในแง่ของการดำเนินงานเมทริกซ์ / เวกเตอร์ นั่นคือวิธี MATLABic นอกจากนี้ยังมีฟังก์ชั่นในตัวจำนวนมากเพื่อกำหนดค่าเริ่มต้นเมทริกซ์เป็นต้นตัวอย่างเช่นมีฟังก์ชั่นones ()ซึ่งจะกำหนดองค์ประกอบทั้งหมดของเมทริกซ์เป็น 1 (ตามส่วนขยายเป็นค่าใด ๆ โดยการคูณ (สเกลาร์ คูณด้วยเมทริกซ์ทุกคน)) มันใช้งานได้กับอาร์เรย์ 3 มิติ (ซึ่งฉันคิดว่าครอบคลุมตัวอย่างที่นี่)
ปีเตอร์มอร์เทนเซ่น

3
@PeterMortensen ปัจจัยใด (โดยประมาณ) ประสิทธิภาพของลูปใน Matlab นั้นเล็กกว่าเมื่อเปรียบเทียบกับ C และ Python? และทำไมเป็นเช่นนั้น? นอกจากนี้ประสิทธิภาพของลูปใน Matlab ยังไม่ดีขึ้นในช่วงหลายปีที่ผ่านมา?
TensoR

3
@PeterMortensen“ โดยปกติปัญหาสามารถแสดงได้ในแง่ของการดำเนินการของเมทริกซ์ / เวกเตอร์” - สำหรับค่าบางอย่างของ“ ปกติ” ใช่ IMO มีความถูกต้องมากกว่าที่จะบอกว่าคนที่ทำงานใน Matlab และคนที่ชอบมีวัฒนธรรมที่ยาวนานในการเพิกเฉยต่อทุกสิ่งที่ไม่สามารถทำได้ด้วยการดำเนินการของเมทริกซ์ / เวกเตอร์มากจนทุกอย่างดูเหมือนจะตอกตะปูพวกเขา . และเราไม่ควรพูดว่า“ เพราะลูปใน Matlab ช้า” แต่“ Matlab ช้า” (มันเกิดขึ้นเพื่อเชื่อมโยงกับไลบรารีเร็วของแอลเอดั้งเดิมที่เขียนใน C และ Fortran)
leftaroundabout

5
ประสิทธิภาพของ for loops แย้ง: matlabtips.com/matlab-is-no-longer-slow-at-for-loops
ohreally

@leftaroundabout True ความกังวลเกี่ยวกับความเร็วในภาษาที่ตีความ (หรือกึ่งตีความ) เป็นตัวบ่งชี้ที่ชัดเจนว่าคุณมีปัญหา XY ที่ทางออกที่แท้จริงคือ "ไม่ใช้ภาษานี้" ข้อยกเว้นคือถ้าคุณกำลังใช้การสร้างรหัสใน Simulink แต่คำถามคือ C ตัวสร้างโค้ดสร้างขึ้นมาและมีประสิทธิภาพเพียงใด
เกรแฮม

คำตอบ:


18

คำตอบสั้น ๆ คุณต้องการให้ดัชนีด้านซ้ายสุดอยู่ในวงในสุด ในตัวอย่างของคุณดัชนีลูปจะเป็น k, j, i และดัชนีอาร์เรย์จะเป็น i, j, k สิ่งนี้เกี่ยวข้องกับวิธีที่ MATLAB จัดเก็บมิติต่าง ๆ ในหน่วยความจำ สำหรับข้อมูลเพิ่มเติมโปรดดูที่ # 13 ของโพสต์ redditนี้


2
หรือใช้ฟังก์ชั่นคน ()
Peter Mortensen

5
@ ตัวอย่างของ OP OP เป็นเพียงตัวอย่างของเล่นของวนรอบที่ทำบางสิ่งบางอย่างและไม่ใช่กรณีการใช้งานจริง
Matt

@Matt คุณถูกต้อง
TensoR

11

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

อันดับแรก MATLAB (และ Fortran แต่ไม่ใช่ภาษาซีและภาษาการเขียนโปรแกรมส่วนใหญ่อื่น ๆ ) จะจัดเก็บอาร์เรย์ในหน่วยความจำใน "ลำดับหลักของคอลัมน์" เช่นถ้า A เป็นเมทริกซ์ขนาด 2 คูณ 3 คูณ 10 รายการจะถูกเก็บไว้ในหน่วยความจำตามลำดับ

A (1,1,1)

A (2,1,1)

A (1,2,1)

A (2,2,1)

A (1,3,1)

A (2,3,1)

A (1,1,2)

A (2,1,2)

...

A (2,3,10)

ตัวเลือกของการเรียงลำดับคอลัมน์หลักนี้โดยพลการ - เราสามารถนำระเบียบ "คำสั่งแถวหลัก" มาใช้ได้อย่างง่ายดายและที่จริงแล้วนั่นคือสิ่งที่ทำในภาษา C และภาษาการเขียนโปรแกรมอื่น ๆ

สิ่งสำคัญที่สองที่คุณต้องเข้าใจคือตัวประมวลผลที่ทันสมัยไม่สามารถเข้าถึงหน่วยความจำทีละตำแหน่ง แต่ให้โหลดและจัดเก็บ "แคชไลน์" ที่ 64 หรือ 128 ไบต์ที่ต่อเนื่องกัน (8 หรือ 16 คู่เลขทศนิยมแม่นยำ) ในเวลาจากหน่วยความจำ ข้อมูลเหล่านี้จะถูกเก็บไว้ชั่วคราวในแคชหน่วยความจำที่รวดเร็วและเขียนออกมาได้ตามต้องการ (ในทางปฏิบัติแล้วสถาปัตยกรรมแคชตอนนี้ค่อนข้างซับซ้อนโดยมีหน่วยความจำแคชมากถึง 3 หรือ 4 ระดับ แต่แนวคิดพื้นฐานสามารถอธิบายได้ด้วยแคชระดับเดียวของการเรียงลำดับที่คอมพิวเตอร์มีในวันที่น้องของฉัน)

A

หากลูปซ้อนกันเพื่อให้วงในสุดอัพเดทตัวห้อยแถวจากนั้นรายการอาร์เรย์จะถูกเข้าถึงในลำดับ A (1,1), A (2,1), A (3,1), ... เมื่อ การเข้าถึงรายการแรก A (1,1) ระบบจะนำบรรทัดแคชที่มี A (1,1), A (2,1), ... , A (8,1) เข้าสู่แคชจากหน่วยความจำหลัก . การวนซ้ำ 8 ครั้งถัดไปของลูปในสุดจะทำงานกับข้อมูลนี้โดยไม่ต้องมีการถ่ายโอนหน่วยความจำหลักเพิ่มเติม

หากเป็นทางเลือกเราจัดโครงสร้างลูปเพื่อให้ดัชนีคอลัมน์แตกต่างกันในวงในสุดจากนั้นรายการของ A จะเข้าถึงได้ในลำดับ A (1,1), A (1,2), A (1,3 ), ... ในกรณีนี้การเข้าถึงครั้งแรกจะนำ A (1,1), A (2,1), ... , A (8,1) เข้าสู่แคชจากหน่วยความจำหลัก แต่ 7/8 ของ รายการเหล่านี้จะไม่ถูกใช้ การเข้าถึง A (1,2) ในการวนซ้ำครั้งที่สองจะทำให้มี 8 รายการเข้ามาจากหน่วยความจำหลักและอื่น ๆ เมื่อถึงเวลาที่โค้ดทำงานให้กับแถวที่ 2 ของเมทริกซ์รายการ A (2,1) อาจถูกล้างออกจากแคชเพื่อหลีกเลี่ยงข้อมูลที่จำเป็นอื่น ๆ เป็นผลให้รหัสกำลังสร้างปริมาณการรับส่งข้อมูล 8 เท่าตามที่จำเป็น

คอมไพเลอร์ที่ปรับให้เหมาะสมบางตัวสามารถปรับโครงสร้างลูปได้โดยอัตโนมัติเพื่อหลีกเลี่ยงปัญหานี้

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

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