- •Об авторе
- •О группе редакторов
- •Предисловие
- •Введение
- •Как использовать эту книгу
- •Загрузка исходного кода CPython
- •Что в исходном коде?
- •Настройка среды разработки
- •IDE или редактор?
- •Настройка Visual Studio
- •Настройка Visual Studio Code
- •Настройка Vim
- •Выводы
- •Компиляция CPython
- •Компиляция CPython на macOS
- •Компиляция CPython на Linux
- •Установка специализированной версии
- •Знакомство с Make
- •Make-цели CPython
- •Компиляция CPython на Windows
- •Профильная оптимизация
- •Выводы
- •Грамматика и язык Python
- •Спецификация языка Python
- •Генератор парсеров
- •Повторное генерирование грамматики
- •Выводы
- •Конфигурация и ввод
- •Конфигурация состояния
- •Структура данных конфигурации среды выполнения
- •Конфигурация сборки
- •Сборка модуля из входных данных
- •Выводы
- •Генерирование конкретного синтаксического дерева
- •Парсер/токенизатор CPython
- •Абстрактные синтаксические деревья
- •Важные термины
- •Пример: добавление оператора «почти равно»
- •Выводы
- •Компилятор
- •Исходные файлы
- •Важные термины
- •Создание экземпляра компилятора
- •Флаги будущей функциональности и флаги компилятора
- •Таблицы символических имен
- •Основная компиляция
- •Ассемблер
- •Создание объекта кода
- •Использование Instaviz для вывода объекта кода
- •Пример: реализация оператора «почти равно»
- •Выводы
- •Цикл вычисления
- •Исходные файлы
- •Важные термины
- •Построение состояния потока
- •Построение объектов кадров
- •Выполнение кадра
- •Стек значений
- •Пример: добавление элемента в список
- •Выводы
- •Управление памятью
- •Выделение памяти в C
- •Проектирование системы управления памятью Python
- •Аллокаторы памяти CPython
- •Область выделения объектной памяти и PyMem
- •Область выделения сырой памяти
- •Нестандартные области выделения памяти
- •Санитайзеры выделенной памяти
- •Арена памяти PyArena
- •Подсчет ссылок
- •Сборка мусора
- •Выводы
- •Параллелизм и конкурентность
- •Модели параллелизма и конкурентности
- •Структура процесса
- •Многопроцессорный параллелизм
- •Многопоточность
- •Асинхронное программирование
- •Генераторы
- •Сопрограммы
- •Асинхронные генераторы
- •Субинтерпретаторы
- •Выводы
- •Объекты и типы
- •Примеры этой главы
- •Встроенные типы
- •Типы объектов
- •Тип type
- •Типы bool и long
- •Тип строки Юникода
- •Словари
- •Выводы
- •Стандартная библиотека
- •Модули Python
- •Модули Python и C
- •Набор тестов
- •Запуск набора тестов в Windows
- •Запуск набора тестов в Linux или macOS
- •Флаги тестирования
- •Запуск конкретных тестов
- •Модули тестирования
- •Вспомогательные средства тестирования
- •Выводы
- •Отладка
- •Обработчик сбоев
- •Компиляция поддержки отладки
- •LLDB для macOS
- •Отладчик Visual Studio
- •Отладчик CLion
- •Выводы
- •Бенчмаркинг, профилирование и трассировка
- •Использование timeit для микробенчмарка
- •Использование набора тестов производительности Python
- •Профилирование кода Python с использованием cProfile
- •Выводы
- •Что дальше?
- •Создание расширений C для CPython
- •Улучшение приложений Python
- •Участие в проекте CPython
- •Дальнейшее обучение
- •Препроцессор C
- •Базовый синтаксис C
- •Выводы
- •Благодарности
Выводы 161
В файле Lib traceback.py можно использовать функцию walk_stack() для получения трассировки:
def walk_stack(f):
"""Обход стека с получением кадра и номера строки для каждого кадра.
Переход осуществляется по ссылке f.f_back из заданного кадра. Если кадр не задан, используется текущий стек.
Обычно используется c StackSummary.extract
"""
if f is None:
f = sys._getframe().f_back.f_back while f is not None:
yield f, f.f_lineno f = f.f_back
В качестве кадра выбирается родитель родителя (sys._getframe().f_back.f_ back), потому что в трассировке не должны присутствовать вызовы walk_ stack() или print_trace(). Указатель f_back отслеживается до вершины стека вызовов.
sys._getframe() — функция Python API для получения атрибута frame текущего потока.
А вот как будет выглядеть стек с тремя кадрами, каждый из которых связан со своим объектом кода и состоянием потока, ссылающимся на текущий кадр:
|
|
|
FRAME 0 |
|
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
f_back |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FRAME 1 |
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
f_back |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
FRAME 2 |
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
frame |
|
|
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ВЫВОДЫ
В этой главе вы познакомились с «мозгом» CPython. Основной цикл вычисления обеспечивает взаимодействие между скомпилированным кодом
Книги для программистов: https://t.me/booksforits
162 Цикл вычисления
Python и базовыми модулями расширения C, библиотеками и системными вызовами.
Некоторые темы этой главы были изложены предельно кратко, так как мы вернемся к ним далее в книге. Например, у интерпретатора CPython есть основной цикл вычисления, но при этом могут работать сразу несколько циклов — параллельно или конкурентно.
В CPython может работать множество циклов вычисления, выполняющих несколько кадров в системе. В одной из следующих глав «Параллелизм и конкурентность» вы увидите, как система стека кадров используется CPython для выполнения на разных ядрах процессора. Кроме того, API объекта кадра CPython позволяет приостанавливать и возобновлять выполнение кадров в форме асинхронного программирования.
Загрузка переменных с использованием стека значений требует выделения памяти и управления ею. Чтобы CPython мог работать эффективно, он должен иметь надежный механизм управления памятью. В следующей главе рассматривается процесс управления памятью и его связь с указателями PyObject, используемыми циклом вычисления.
Книги для программистов: https://t.me/booksforits