Halo, Habr!
Saya ingin memberi tahu Anda tentang peristiwa luar biasa yang saya pelajari beberapa bulan lalu. Ternyata salah satu utilitas python populer telah didistribusikan selama lebih dari setahun sebagai binari yang dikompilasi langsung dari python. Dan ini bukan tentang pengemasan dangkal oleh beberapa PyInstaller , tetapi tentang kompilasi Ahead-of-time yang jujur dari seluruh paket python. Jika Anda sama terkejutnya dengan saya, selamat datang di kucing.
Izinkan saya menjelaskan mengapa menurut saya acara ini benar-benar luar biasa. Ada dua jenis kompilasi: Ahead-of-time (AOT) , ketika semua kode dikompilasi sebelum memulai program, dan Just in time compiler (JIT) , ketika program secara langsung dikompilasi untuk arsitektur prosesor yang diperlukan selama pelaksanaannya . Dalam kasus kedua, peluncuran awal program dilakukan oleh mesin virtual atau juru bahasa.
Jika kita mengelompokkan bahasa pemrograman populer berdasarkan jenis kompilasi, kita mendapatkan daftar berikut:
Kompiler sebelumnya: C, C ++, Rust, Kotlin, Nim, D, Go, Dart;
Penyusun waktu tepat: Lua, C #, Groovy, Dart.
Tidak ada kompiler JIT di luar kotak di python, tetapi perpustakaan terpisah yang menyediakan kesempatan seperti itu telah ada sejak lama.
, : . : Kotlin JIT JavaVM, AOT Kotlin/Native. Dart ( 2). A JIT-, .
, , . .
JIT , . JIT . AOT , ? , .
, , . mypy - python-.
2019 , . — mypyc. , “ 4 Python-” mypy ( : 1, 2, 3). mypyc: mypy python- Dropbox, , . , : go cython. — AOT python-.
, mypy , . mypy “” python, , mypyc .
, , python-. Python c 3.4 , mypy . , python , AOT . , mypyc !
bubble_sort
“”. lib.py:
def bubble_sort(data):
n = len(data)
for i in range(n - 1):
for j in range(n - i - 1):
if data[j] > data[j + 1]:
buff = data[j]
data[j] = data[j + 1]
data[j + 1] = buff
return data
, mypyc . , mypyc. , mypy, mypyc ! mypyc, :
> mypyc lib.py
:
.mypy_cache
— mypy , mypyc mypy AST;
build
— ;
lib.cpython-38-x86_64-linux-gnu.so
— . CPython Extension.
CPython Extension — CPython , /C++. , CPython lib. , python.
:
python ;
.so , mypyc gcc (gcc python-dev ).
lib.cpython-38-x86_64-linux-gnu.so
lib.py , .
. main.py :
import lib
data = lib.bubble_sort(list(range(5000, 0, -1)))
assert data == list(range(1, 5001))
:
|
|
|
real 5.68 user 5.60 sys 0.01 |
real 2.78 user 2.73 sys 0.01 |
(~ 2 ), , . .
“ ”, . , .
sum(a, b)
:
def sum(a, b):
return a + b
:
int sum(int a, int b) {
return a + b;
}
c ( ):
PyObject *CPyDef_sum(PyObject *cpy_r_a, PyObject *cpy_r_b){
return PyNumber_Add(cpy_r_a, cpy_r_b);
}
, . -, , PyObject, CPython . , , : , , , , . mypyc?
, : CPython . PyNumber_Add — Python, , Python .
CPython c Extension :
— - sum A, B;
— , , A + B;
— ;
— , - .
: , , .
, , , mypyc , .
sum(a: int, b: int)
, python, , , . , . , CPython - Extension. ?
, , , , CPython. mypyc , . mypyc , , sum. , , . , -, :
def sum(a: int, b: int):
return a + b
C ( ):
PyObject *CPyDef_sum(CPyTagged cpy_r_a, CPyTagged cpy_r_b) {
CPyTagged cpy_r_r0;
PyObject *cpy_r_r1;
cpy_r_r0 = CPyTagged_Add(cpy_r_a, cpy_r_b);
cpy_r_r1 = CPyTagged_StealAsObject(cpy_r_r0);
return cpy_r_r1;
}
, : , , . , .
CPyDef_sum PyObject, CPyTagged. int, CPython, mypyc, . , sum int .
CPyTaggetAdd PyNumber_Add. mypyc. CPyTaggetAdd, , a b, int, , :
if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
CPyTagged sum = left + right;
if (likely(!CPyTagged_IsAddOverflow(sum, left, right))) {
return sum;
}
}
, CPython - Extension :
— - sum A, B;
— , .
bubble_sort(data: List[int])
, . , data:
def bubble_sort(data: List[int]):
…
:
|
, |
|
real 5.68 user 5.60 sys 0.01 |
real 2.78 user 2.73 sys 0.01 |
real 1.32 user 1.30 sys 0.01 |
, , , !
mypyc
, , . mypyc : , , , mypy. mypy . python-, , .
, , :
;
monkey patching;
Mypy , .
. , , abc. , . , gcc , , , . , , 20 % , .
Nuitka
, . Nuitka . , Nuitka Python ++ , Python Extension. , CPython libpython.
Nuitka , . mypy .
, mypy : , “ ”, PyCharm . , mypy. , . , python. mypy — , . , CPython , , . (, mypyc ). , mypyc , , , - , mypyc, , , mypy.
P.S.
, python, . , mypyc, , , .
UPD
, python - Cython, python ( cython-). cython , (real 1.82) mypyc . .