นอกเหนือจากเวลาเก็บตัวแปรท้องถิ่น / ส่วนกลางการคาดการณ์ opcodeทำให้ฟังก์ชั่นเร็วขึ้น
ตามที่คำตอบอื่น ๆ อธิบายฟังก์ชั่นใช้STORE_FAST
opcode ในลูป นี่คือโค้ดไบต์สำหรับการวนซ้ำของฟังก์ชัน:
>> 13 FOR_ITER 6 (to 22) # get next value from iterator
16 STORE_FAST 0 (x) # set local variable
19 JUMP_ABSOLUTE 13 # back to FOR_ITER
โดยปกติเมื่อมีการเรียกใช้โปรแกรม Python จะดำเนินการแต่ละ opcode ซึ่งกันและกันติดตามการทำงานของ stack และ preforming การตรวจสอบอื่น ๆ ใน stack frame หลังจากดำเนินการแต่ละ opcode การคาดการณ์ของ Opcode หมายความว่าในบางกรณี Python สามารถข้ามไปยัง opcode ถัดไปได้โดยตรงดังนั้นจึงไม่ควรใช้โอเวอร์เฮดนี้
ในกรณีนี้ทุกครั้งที่ Python เห็นFOR_ITER
(ด้านบนของลูป) มันจะ "ทำนาย" ซึ่งSTORE_FAST
เป็น opcode ถัดไปที่จะต้องดำเนินการ งูหลามแล้ว peeks ที่ opcode STORE_FAST
ต่อไปและหากการทำนายถูกต้องมันกระโดดตรงไปยัง นี่คือผลของการบีบสอง opcode เป็น opcode เดียว
ในทางตรงกันข้ามSTORE_NAME
opcode จะถูกใช้ในการวนซ้ำในระดับโลก Python ไม่ *ทำการคาดคะเนที่คล้ายกันเมื่อเห็น opcode นี้ แต่จะต้องกลับไปที่ด้านบนของลูปการประเมินผลซึ่งมีผลกระทบอย่างชัดเจนต่อความเร็วในการดำเนินการลูป
หากต้องการให้รายละเอียดทางเทคนิคเพิ่มเติมเกี่ยวกับการเพิ่มประสิทธิภาพนี้ต่อไปนี้เป็นคำกล่าวจากceval.c
ไฟล์ ("เอ็นจิ้น" ของเครื่องเสมือนของ Python):
opcodes บางตัวมีแนวโน้มที่จะมาเป็นคู่จึงทำให้สามารถทำนายรหัสที่สองเมื่อรันครั้งแรก ยกตัวอย่างเช่น
มักจะตามมาด้วยGET_ITER
FOR_ITER
และFOR_ITER
มักจะตามมาด้วยSTORE_FAST
UNPACK_SEQUENCE
หรือ
การตรวจสอบการคาดการณ์ทำให้เสียค่าใช้จ่ายในการทดสอบความเร็วสูงเดียวของตัวแปร register กับค่าคงที่ หากการจับคู่เป็นไปได้ดีการคาดคะเนสาขาภายในของโปรเซสเซอร์จะมีโอกาสสูงที่จะประสบความสำเร็จส่งผลให้เกิดการเปลี่ยนแปลงเกือบเป็นศูนย์เหนือ opcode ถัดไป การทำนายที่ประสบความสำเร็จจะช่วยประหยัดการเดินทางผ่านการวนรอบ eval รวมทั้งกิ่งไม้ที่ไม่สามารถคาดการณ์ได้สองแบบการHAS_ARG
ทดสอบและตัวเรือนสวิตช์ เมื่อรวมกับการทำนายสาขาภายในของตัวประมวลผลความสำเร็จPREDICT
มีผลทำให้การใช้งานสอง opcode ราวกับว่าพวกมันเป็น opcode ใหม่เพียงครั้งเดียว
เราสามารถเห็นได้ในซอร์สโค้ดสำหรับFOR_ITER
opcode ตรงกับที่การคาดการณ์STORE_FAST
ทำ:
case FOR_ITER: // the FOR_ITER opcode case
v = TOP();
x = (*v->ob_type->tp_iternext)(v); // x is the next value from iterator
if (x != NULL) {
PUSH(x); // put x on top of the stack
PREDICT(STORE_FAST); // predict STORE_FAST will follow - success!
PREDICT(UNPACK_SEQUENCE); // this and everything below is skipped
continue;
}
// error-checking and more code for when the iterator ends normally
PREDICT
ขยายตัวฟังก์ชั่นif (*next_instr == op) goto PRED_##op
คือเราก็ข้ามไปยังจุดเริ่มต้นของ opcode ที่คาดการณ์ไว้ ในกรณีนี้เรากระโดดที่นี่:
PREDICTED_WITH_ARG(STORE_FAST);
case STORE_FAST:
v = POP(); // pop x back off the stack
SETLOCAL(oparg, v); // set it as the new local variable
goto fast_next_opcode;
ตัวแปรโลคอลได้รับการตั้งค่าแล้วและ opcode ถัดไปจะพร้อมใช้งานสำหรับการดำเนินการ Python ดำเนินการต่อผ่าน iterable จนกว่าจะถึงจุดสิ้นสุดทำให้การทำนายผลสำเร็จทุกครั้ง
หน้าวิกิพีเดียหลามมีข้อมูลเพิ่มเติมเกี่ยวกับวิธีการ CPython ทำงานของเครื่องเสมือน