Yerel / global değişken mağaza sürelerinin yanı sıra, opcode tahmini işlevi daha hızlı hale getirir.
Diğer cevapların açıkladığı gibi, fonksiyon STORE_FASTdöngüdeki opcode'u kullanır . İşte işlevin döngüsü için bayt kodu:
>> 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
Normalde bir program çalıştırıldığında, Python her opcode'u birbiri ardına yürütür, bir yığının kaydını tutar ve her opcode yürütüldükten sonra yığın karesinde diğer kontrolleri önceden yapar. Opcode tahmini, bazı durumlarda Python'un bir sonraki opcode'a doğrudan atlayabileceği ve böylece bu ek yükün bir kısmından kaçınabileceği anlamına gelir.
Bu durumda, Python her FOR_ITERdöngüde (döngünün üst kısmı) her gördüğünde STORE_FAST, yürütmesi gereken bir sonraki opcode olan "tahmini" olur. Python daha sonra bir sonraki opcode'a göz atar ve tahmin doğruysa doğrudan doğruya atlar STORE_FAST. Bunun, iki opodu tek bir opcode olarak sıkma etkisi vardır.
Öte yandan, STORE_NAMEopcode döngüde global düzeyde kullanılır. Python, bu opcode'u gördüğünde benzer tahminlerde bulunmaz * . Bunun yerine, döngünün yürütüldüğü hız için belirgin etkileri olan değerlendirme döngüsünün en üstüne geri dönmelidir.
Bu optimizasyon hakkında daha fazla teknik ayrıntı vermek için, ceval.cdosyadan bir alıntı (Python'un sanal makinesinin "motoru"):
Bazı opodlar çiftler halinde gelir, böylece ilk kod çalıştırıldığında ikinci kodu tahmin etmeyi mümkün kılar. Örneğin
GET_ITER, genellikle onu takip eder FOR_ITER. Ve FOR_ITERgenellikleSTORE_FAST veya ile devam eder UNPACK_SEQUENCE.
Tahmini doğrulamak, bir kayıt değişkeninin bir sabite karşı tek bir yüksek hızlı testine mal olur. Eşleştirme iyiyse, işlemcinin kendi dahili şube tahmininin yüksek bir başarı olasılığı vardır ve bu da bir sonraki opcode'a neredeyse sıfır ek yüke geçişle sonuçlanır. Başarılı bir tahmin, öngörülemeyen iki dalı olan HAS_ARGtest ve anahtar durumu da dahil olmak üzere eval-loop üzerinden bir yolculuk kaydeder . İşlemcinin dahili şube tahmini ile birleştiğinde, başarılı bir şekilde PREDICT, iki opcodun, gövdeleri birleştirilmiş yeni bir tek opcodemuş gibi çalıştırması etkisi vardır.
FOR_ITEROpcode'un kaynak kodunda tam olarak tahminin STORE_FASTyapıldığı yeri görebiliriz:
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
PREDICTFonksiyon için genişler if (*next_instr == op) goto PRED_##opbiz sadece tahmin işlem kodu başlangıcına atlamak yani. Bu durumda, buraya atlıyoruz:
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;
Yerel değişken ayarlanmıştır ve bir sonraki opcode yürütülmeye hazırdır. Python her seferinde başarılı bir tahminde bulunarak sonuna kadar tekrarlanabilir.
Python wiki sayfası CPython sanal makine nasıl çalıştığı hakkında daha fazla bilgi vardır.