สับสนระหว่างพื้นที่ชั่วคราวและเชิงพื้นที่ในโค้ดชีวิตจริง

ฉันกำลังอ่านคำถามนี้ ฉันต้องการถามเพิ่มเติมเกี่ยวกับโค้ด ที่เขาแสดงให้เห็นคือ

for(i = 0; i < 20; i++)
    for(j = 0; j < 10; j++)
        a[i] = a[i]*j;

คำถามคือ

  1. ฉันเข้าใจสถานที่ชั่วคราว ฉันคิดว่าการอ้างอิงถึง i และ j ควรเป็นสถานที่ชั่วคราว ฉันถูกไหม?
  2. ฉันยังเข้าใจตำแหน่งเชิงพื้นที่ด้วย เนื่องจากคำถามที่ฉันเชื่อมโยงคำตอบที่อ้างอิงถึง a[i] ควรเป็นตำแหน่งเชิงพื้นที่ ฉันถูกไหม?
  3. #P3#
    #P4#
    #P5#

person Community    schedule 18.10.2011    source แหล่งที่มา


คำตอบ (4)


ก่อนอื่น การอ้างอิงถึง var อาจเป็น ท้องถิ่นชั่วคราว หรือ ท้องถิ่นเชิงพื้นที่ ไม่ใช่ ท้องถิ่นชั่วคราว ซึ่งเป็นไวยากรณ์ที่ไม่เหมาะสม จุดรอง.

ตอนนี้ถึงคำถามของคุณ

  1. หลักการของ ตำแหน่งชั่วคราว ระบุว่าคำสั่งสองคำสั่งอ้างอิงตำแหน่งเดียวกันภายในกรอบเวลาที่ค่อนข้างสั้น ตัวอย่างเช่น ในโค้ดที่ให้มา a[i] จะถูกอ้างอิงบ่อยครั้ง โดยมีคำสั่งอย่าง a[i] = a[i] * 2 และ a[i] = a[i] * 3 ที่ถูกดำเนินการใกล้กันมาก หากเราดูขอบเขตนี้ เราสามารถพูดได้ว่าการอ้างอิงถึง j และ a[i] เป็นแบบชั่วคราว การอ้างอิงถึง i เป็นแบบชั่วคราวเช่นกัน เนื่องจาก i ถูกอ้างอิงทุกครั้งที่ a[i] เป็น อย่างไรก็ตาม หากบรรทัดสุดท้ายของโค้ดที่กำหนดอ่านค่าประมาณ a[j] = a[j] * j การอ้างอิงถึง i จะไม่เป็นแบบชั่วคราว อย่างน้อยก็อยู่ในขอบเขตของลูปด้านใน[1]

  2. หลักการของ ตำแหน่งเชิงพื้นที่ ระบุว่าคำสั่งสองคำสั่งอ้างอิงตำแหน่งหน่วยความจำที่อยู่ติดกัน การอ้างอิงถึง a[i] เป็นตัวอย่างที่ดีของสิ่งนี้ ดังที่ใครๆ ก็สามารถสันนิษฐานได้ (โดยส่วนใหญ่) ว่า a[0] และ a[1] จะอยู่ติดกันในหน่วยความจำ

  3. โดยพื้นฐานแล้วสองข้อแรกครอบคลุมเรื่องนี้ แต่ข้อความที่ยกมานั้นถูกต้อง และโค้ดยังแสดงให้เห็นถึงตำแหน่งเชิงพื้นที่ด้วย

[1] - โดยทั่วไป เมื่อคุณกำลังพูดถึงท้องถิ่น มันจะอยู่ในบริบทของระดับที่กำหนดในลำดับชั้นของหน่วยความจำ ไม่ว่าจะเป็น RAM หรือแคช L1 หรือสิ่งที่คุณมี โดยรวมแล้ว ยกเว้นในแง่ที่จำกัดที่สุด การอ้างอิงถึงทั้ง i และ j เป็นแบบชั่วคราว

person brc    schedule 18.10.2011
comment
ขอบคุณสำหรับคำตอบ. คุณช่วยอธิบายแนวคิดของฉันเกี่ยวกับตัวแปรและตำแหน่งได้ไหม ตัวแปร j จะเพิ่มขึ้นในแต่ละครั้งที่ลูปภายในดำเนินการ และจะได้รับค่าใหม่ การรับค่าใหม่ไม่ใช่พื้นที่เชิงพื้นที่ (แม้ว่าจะเพิ่มขึ้นทีละ 1 ในแต่ละครั้งก็ตาม) - person ; 18.10.2011
comment
@Akito ถูกต้อง ตำแหน่งเชิงพื้นที่สามารถเกิดขึ้นได้ระหว่างตำแหน่ง ต่างกัน สองแห่งในหน่วยความจำเท่านั้น เนื่องจาก j อ้างถึงตำแหน่งเดียวกันในแต่ละครั้ง การอ้างอิงถึง j จึงไม่ใช่เชิงพื้นที่ - person brc; 18.10.2011
comment
คุณช่วยอธิบายรายละเอียดเกี่ยวกับคำอ้างอิงที่ใช้ด้วยได้ไหม นั่นหมายความว่าอย่างไร? - person ; 18.10.2011
comment
การอ้างอิงถึงตัวแปรเช่น j หมายความว่ามีการเข้าถึงหรือแก้ไขค่า j ดังนั้น a[i] คือการอ้างอิงทั้งค่าของ i และค่าใดก็ตามที่เก็บไว้ใน a[i] - person brc; 18.10.2011

เขียนคำตอบนี้เนื่องจากฉันไม่เข้าใจแม้ว่าจะอ่านคำตอบอื่น ๆ ของคำถามนี้ คำถามอื่น ๆ และวิกิพีเดียแล้ว (นั่นทำให้เกิดความสับสนมากขึ้น)

ฉันคิดว่าเราใช้เวลาและพลังงานอย่างมากในการทำความเข้าใจคำศัพท์ที่ค่อนข้างสับสนหรือซับซ้อนในกรณีนี้ ฉันพบว่ามันง่ายกว่าที่จะเข้าใจเมื่อฉันไม่ได้ใส่ใจกับคำว่า 'พิเศษ' และ 'ชั่วคราว'

เริ่มจากพื้นฐานกันก่อน

ลองทำความเข้าใจว่าแคชคืออะไร - สถานที่ที่เข้าถึงได้เร็วกว่าหน่วยความจำหลัก เจ๋งเลย แต่สถานที่แห่งนี้มีจำนวนจำกัดและมีราคาแพง ดังนั้นจึงควรใช้อย่างชาญฉลาด แต่คุณ (หรือ OS) จะตัดสินใจได้อย่างไรว่าจะใส่อะไรในแคชและอะไรจะไม่ใส่? น่าจะมีวิธีที่จะรู้ว่าเราต้องการอะไรในอนาคต.. อ่า การคาดการณ์ในอนาคต! (Minority Report! กดกริ่งบ้างไหม?).

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

ในพื้นที่อื่นถ้าโค้ดใช้โครงสร้างข้อมูลเชิงเส้นใดๆ (ตัวอย่าง: Array) และนั่นก็วนซ้ำด้วยการเพิ่มดัชนี จะเห็นได้ง่ายว่าแม้ว่าความต้องการปัจจุบันจะเป็นเพียงตำแหน่งที่ 3 (ตัวอย่าง) ของ โครงสร้างข้อมูลนี้ ในไม่ช้าตำแหน่งถัดไปก็เป็นสิ่งจำเป็นเช่นกัน เนื่องจากดัชนีเพิ่มขึ้น 1 สำหรับโครงสร้างข้อมูลเชิงเส้นนั้น คงจะดีไม่น้อยหากเรานำข้อมูลเข้ามาในสถานที่ถัดไปสองสามแห่งด้วย นี่คือหลักการเบื้องหลังพื้นที่พิเศษ ตำแหน่งไม่กี่แห่งถัดมาสามารถนำเข้าสู่แคชได้เนื่องจากเป็นตำแหน่งในพื้นที่เฉพาะ

แนวคิดของพื้นที่นั้นโดยพื้นฐานแล้วคือการระบุข้อมูลและคำแนะนำในการนำเข้าแคช เพื่อให้เราสามารถลดการพลาดแคชและใช้สถานที่พิเศษนี้ได้อย่างมีประสิทธิภาพ

person Saurabh Patil    schedule 21.07.2018
comment
อย่างไรก็ตาม มี 2 วิธีในการใช้ประโยชน์จากพื้นที่เชิงพื้นที่: 1) บรรทัดแคชเก็บหลายรายการ ดังนั้นการตอบสนอง 1 คำขอจึงเตรียมแคชสำหรับคำขอใกล้เคียง 2) การดึงข้อมูลล่วงหน้า: ตรวจจับรูปแบบการเข้าถึงตามลำดับ และเริ่มโหลดบรรทัดแคชที่จำเป็นในไม่ช้า ก่อนที่จะพบกับความต้องการที่พลาดไป CPU มีตรรกะการดึงฮาร์ดแวร์ล่วงหน้าสำหรับแคช L1/L2/L3 แคชซอฟต์แวร์ (เช่น ดิสก์แคชที่จัดการโดย OS) จำเป็นต้องมีตรรกะการดึงข้อมูลล่วงหน้าในซอฟต์แวร์ - person Peter Cordes; 22.07.2018
comment
@PeterCordes: ขอบคุณสำหรับประเด็นเหล่านั้น 1. ไม่เข้าใจสิ่งที่คุณหมายถึงโดยบรรทัดแคชมีหลายบรรทัด - ฉันต้องขาดอะไรบางอย่างพื้นฐาน โปรดอธิบายอย่างละเอียด ฉันล้มเหลวในหลักสูตรไมโครโปรเซสเซอร์ระหว่างที่ฉันสำเร็จการศึกษา :) 2. ดังนั้นแคช L1/L2/L3 จึงไม่ใช่ OS จัดการ? - person Saurabh Patil; 12.12.2018
comment
รายการ หลายรายการ เช่น ints ขนาด 16 คำในบรรทัดแคช 64 ไบต์ และไม่ แคช CPU ไม่ได้รับการจัดการระบบปฏิบัติการ คำขอแคชคือคำสั่งในการโหลดหรือจัดเก็บ และการพลาดแคชนั้นบ่อยเกินไปที่จะจัดการกับการพลาดในซอฟต์แวร์ แม้จะเป็นเพียง L3 ก็ตาม แคชที่ใช้ร่วมกันที่เชื่อมโยงกันมีความสำคัญสำหรับหลายคอร์ในการสื่อสารอย่างมีประสิทธิภาพ ดังนั้นคุณจึงจำเป็นต้องมี HW จริงๆ เพื่อใช้การเชื่อมโยงกันของแคช MESI - person Peter Cordes; 12.12.2018
comment
หลายรายการ (และคำแนะนำที่ฉันเดา?) เข้าใจแล้ว. กลับมาที่พื้นที่เฉพาะ คุณกำลังแนะนำในประเด็นที่ 1 ของคุณว่าการตัดสินใจเกิดขึ้นที่ระดับบรรทัด ไม่ใช่ระดับรายการ และรายการถัดไปที่โหลดจะเป็นคำแนะนำเริ่มต้นถัดไปโดยไม่มีการตัดสินใจจริง (โดย CPU/HW) - person Saurabh Patil; 12.12.2018

วงรอบนอกเป็นตัวอย่างของพื้นที่เฉพาะ โดยจะเพิ่มที่อยู่ของการเรียก for-loop ภายในตามลำดับ

วงในแสดงถึงตำแหน่งชั่วคราว มีการเข้าถึงที่อยู่หน่วยความจำเดียวกัน 10 ครั้งติดต่อกัน และคูณด้วย j ในแต่ละครั้ง

สำหรับคำถามสองข้อแรกของคุณ ทั้ง i และ j (ตัวนับลูป) เป็นตัวอย่างที่ดีของพื้นที่ชั่วคราว

Locality คือการวัดที่ใช้โดยแคชเพื่อลดการเรียกไปยังหน่วยความจำ หากคำสั่งจำเป็นต้องทราบค่าของที่อยู่หน่วยความจำที่ไม่ได้อยู่ในแคช คำสั่งนั้นจะเข้าถึงหน่วยความจำและจัดเก็บตำแหน่งหน่วยความจำโดยรอบทั้งหมดไว้ในแคชเช่นกัน

person Steve Barna    schedule 18.10.2011

เริ่มต้นด้วยการกำหนดทั้งสถานที่ชั่วคราวและเชิงพื้นที่

ตำแหน่งชั่วคราว - ตำแหน่งชั่วคราวหมายความว่าข้อมูลปัจจุบันหรือคำสั่งที่กำลังดึงข้อมูลอาจจำเป็นในไม่ช้า ดังนั้นเราจึงควรจัดเก็บข้อมูลหรือคำสั่งนั้นไว้ในหน่วยความจำแคช เพื่อที่เราจะได้ไม่ต้องค้นหาข้อมูลเดียวกันในหน่วยความจำหลักอีกครั้ง และช่วยประหยัดเวลา

ตำแหน่งเชิงพื้นที่ - ตำแหน่งเชิงพื้นที่หมายถึงคำสั่งหรือข้อมูลที่ใกล้กับตำแหน่งหน่วยความจำปัจจุบันที่กำลังดึงข้อมูล อาจจำเป็นต้องใช้เร็วๆ นี้ในอนาคตอันใกล้นี้

sum = 0;
for (i = 0; i < arr.length; i++)
  sum += arr[i];
return sum;

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

ตอนนี้ดูตัวอย่างนี้

for(i = 0; i < 20; i++)
    for(j = 0; j < 10; j++)
        a[i] = a[i]*j;

ที่นี่เราเห็นพื้นที่ชั่วคราวในขณะที่ a[i] ในวงที่สองถูกใช้ซ้ำแล้วซ้ำอีก จากนั้นตัวแปร j จะถูกเข้าถึงตามลำดับซึ่งแสดงพื้นที่เชิงพื้นที่

person Shubham Jain    schedule 15.02.2019
comment
ในตัวอย่างที่ 2 ของคุณ j เป็นสเกลาร์ ดังนั้น j ทั้งหมดจึงเข้าถึงได้ในคราวเดียว นั่นคือตำแหน่งชั่วคราวสำหรับ a[i] และ j ในวงใน (แน่นอนว่าคอมไพเลอร์ที่เหมาะสมใด ๆ จะเก็บไว้ในรีจิสเตอร์สำหรับลูปภายใน ไม่ใช่จัดเก็บ / โหลดซ้ำเว้นแต่คุณจะปิดการใช้งานการปรับให้เหมาะสม แต่สันนิษฐานว่าคุณหมายถึงสิ่งนี้เป็นรหัสเทียมสำหรับ asm ไม่ใช่ C จริงที่จะคอมไพล์ด้วยคอมไพเลอร์ที่ปรับให้เหมาะสม เพราะดี คอมไพเลอร์จะคลี่ลูปด้านในออกจนสุดแล้วแปลงเป็น a[i] *= 0*1*2*3*4*5*6*7*8*9 เช่น คูณ a[i] ด้วยค่าคงที่เวลาคอมไพล์) จริงๆ แล้วเป็นเพียง a[i] = 0 เพราะคุณรวม 0 เป็นตัวประกอบ - person Peter Cordes; 15.02.2019