Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Python Opcodes

Python Opcodes

Артём Апалько (RedMadRobot backend-dev) @ Moscow Python Meetup 45
"Обзорный доклад по опкодам в питоне. Изменения в Python 3.6 (изменение размера, оптимизация branch-prediction)".
Видео: http://www.moscowpython.ru/meetup/45/python-opcodes/

Moscow Python Meetup

May 25, 2017
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. 4

  2. 1. Лексический анализ - исходный код в токены; 2. Парсинг

    - токены в АСД; 3. Компиляция - АСД в байткод; 4. Интерпретация - исполняет байткод. 5
  3. Объекты функций и объектные модули Объектный модуль файл с промежуточным

    представлением модуля программы в результате обработки исходного кода компилятором. >>> modulo.__code__ <code object modulo at 0x102a74660, file "<stdin>", line 1> >>> dir(modulo.__code__) ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames'] 7
  4. Байткод >>> modulo.__code__.co_varnames ('a', ‘b') >>> modulo.__code__.co_code b’|\x00|\x01\x16\x00S\x00’ [format(b, 'b').zfill(8)

    for b in modulus.__code__.co_code] ['01111100', '00000000', '01111100', '00000001', '00010110', '00000000', '01010011', ‘00000000'] >>> [int(b) for b in modulo.__code__.co_code ] [124, 0, 0, 124, 1, 0, 22, 83] 8
  5. Используем dis >>> dis.dis(modulo) 2 0 LOAD_FAST 0 (a) 3

    LOAD_FAST 1 (b) 6 BINARY_MODULO 7 RETURN_VALUE 2 - номер строки в исходном коде 0, 3, 6, 7 - смещение команд в байткоде LOAD_FAST, BINARY_MODYLO - название опкода 0, 1 - позиция аргумента в пространстве имен 9
  6. 11

  7. ceval.c TARGET(BINARY_MODULO) { PyObject *divisor = POP(); PyObject *dividend =

    TOP(); PyObject *res; if (PyUnicode_CheckExact(dividend) && ( !PyUnicode_Check(divisor) || PyUnicode_CheckExact(divisor))) { // fast path; string formatting, but not if the RHS is a str subclass // (see issue28598) res = PyUnicode_Format(dividend, divisor); } else { res = PyNumber_Remainder(dividend, divisor); } Py_DECREF(divisor); Py_DECREF(dividend); SET_TOP(res); if (res == NULL) goto error; DISPATCH(); } 12
  8. Итого • Опкод - инструкция интерпретатору (1 байт без аргументов

    и 3 байта с аргументами); • Интерпретатор CPython - цикл внутри которого switch по опкодам 13
  9. Major new features of the 3.6 series, compared to 3.5

    PEP 468, Preserving Keyword Argument Order PEP 487, Simpler customisation of class creation PEP 495, Local Time Disambiguation PEP 498, Literal String Formatting PEP 506, Adding A Secrets Module To The Standard Library PEP 509, Add a private version to dict PEP 515, Underscores in Numeric Literals PEP 519, Adding a file system path protocol PEP 520, Preserving Class Attribute Definition Order PEP 523, Adding a frame evaluation API to CPython PEP 524, Make os.urandom() blocking on Linux (during system startup) PEP 525, Asynchronous Generators (provisional) PEP 526, Syntax for Variable Annotations (provisional) PEP 528, Change Windows console encoding to UTF-8 PEP 529, Change Windows filesystem encoding to UTF-8 PEP 530, Asynchronous Comprehensions 14
  10. Байткод 3.5 vs 3.6 Python 3.5 2 0 LOAD_FAST 0

    (a) 3 LOAD_FAST 1 (b) 6 BINARY_MODULO 7 RETURN_VALUE [124,0,0,124,1,0,22,83] Python 3.6 2 0 LOAD_FAST 0 (a) 2 LOAD_FAST 1 (b) 4 BINARY_MODULO 6 RETURN_VALUE [124,0,124,1,22,0,83,0] 16
  11. • Не нужно считать на сколько сдвинуть указатель инструкции; •

    Экономия памяти для большинства случаев 17
  12. Benchmarks Faster (27): - unpack_sequence: 1.11x faster - simple_logging: 1.11x

    faster - silent_logging: 1.10x faster - formatted_logging: 1.09x faster - raytrace: 1.08x faster - chaos: 1.08x faster - etree_process: 1.08x faster - call_simple: 1.07x faster - mako_v2: 1.07x faster - tornado_http: 1.07x faster - nqueens: 1.07x faster - regex_compile: 1.06x faster - pathlib: 1.06x faster - 2to3: 1.06x faster - richards: 1.05x faster - spectral_norm: 1.05x faster - etree_generate: 1.05x faster - chameleon_v2: 1.04x faster - pickle_list: 1.03x faster - pickle_dict: 1.03x faster - regex_v8: 1.03x faster - go: 1.03x faster - call_method: 1.03x faster - django_v3: 1.03x faster - telco: 1.02x faster - json_load: 1.02x faster - call_method_unknown: 1.02x faster Slower (1): - fannkuch: 1.07x slower Not significat (14): - unpickle_list - startup_nosite - regex_effbot - pidigits - normal_startup - nbody - meteor_contest - json_dump_v2 - float - fastunpickle - fastpickle - etree_parse - etree_iterparse - call_method_slots 19