Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Модуль 7.2 — Async Rust и Python

Слайды

Упражнение 7.2.1: Проверка окружения

7.2.1.A: Установка инструментов ⭐

Следуйте инструкциям по установке инструмента сборки Maturin: https://pyo3.rs/v0.21.2/getting-started. Рекомендуем использовать pyenv: https://github.com/pyenv/pyenv, но pyenv работает только в UNIX и WSL. Конечно, можно использовать и любой другой менеджер виртуальных окружений.

Перейдите в терминале в папку exercises/7-rust-for-data-science/1-rust-from-python/1-hello-world/. Создайте и активируйте виртуальное окружение и установите всё необходимое. Если вы используете pyenv, выполните следующие команды:

$ pyenv activate pyo3
$ pip install maturin
$ pip install asyncio
$ pip install aiofiles

7.2.1.B: Пробный запуск ⭐

Если всё прошло успешно, вы сможете собрать этот проект в расширение для Python:

$ maturin develop
$ python test.py

Скрипт test.py заканчивается вызовом функции, которая безусловно выбрасывает исключение, поэтому ожидается, что скрипт завершится необработанным исключением.

Теперь попробуйте запустить и test_async.py и понаблюдайте за его поведением.

7.2.1.C: Параллельный запуск футур ⭐⭐

В Python-скрипте для выполнения нескольких awaitable-объектов можно использовать asyncio.gather. Создайте несколько футур print_sleep с разной длительностью сна, запустите их через asyncio.gather и понаблюдайте за поведением.

Упражнение 7.2.2: Потоковый JSON

Вот полезный крейт: Struson. Он позволяет (де)сериализовать JSON-объекты потоково, то есть не держать все данные в памяти. Это контрастирует с отличной библиотекой serde_json, которая очень удобна, но не позволяет легко (де)сериализовать данные потоком. Мы создадим обёртку над Struson, которой можно будет пользоваться из Python.

Представим, что у нас есть поток JSON. Он может приходить от кого-то из интернета или от другого процесса на этой машине. Или, например, из файла. Поток состоит из данных такого вида:

[
    {
        "lhs": {
            "d":[
                1, 2, 3, 4,
                5, 6, 7, 8,
                9, 10, 11, 12
            ],
            "n": 3
        },

        "op": [
            {
                "code": "dot",
                "rhs": {
                    "d": [
                        13, 14, 15, 16,
                        17, 18, 19, 20,
                        21, 22, 23, 24
                    ],
                    "n": 3
                }
            }
        ]
    }
]

Этот JSON — массив объектов, каждый из которых описывает следующее:

  • lhs: матрица с m строками и n столбцами. m можно вычислить по n и длине d. В данном случае m = len / n = 12 / 3 = 4.
  • op: последовательность операций, которые нужно выполнить над lhs и, если операция принимает два операнда, над полем rhs. Поле code задаёт операцию, которая должна более или менее соответствовать методам типа Matrix из nalgebra. В данном случае нужно выполнить метод Matrix::dot, который, и не без оснований, описан как «скалярное произведение двух векторов или матриц (рассматриваемых как векторы)».

Наша библиотека должна потоково десериализовать каждый входящий объект из потока байтов asyncio, применить заданную операцию и передать результат дальше.

Упражнение 7.2.2.A: Попробуйте ⭐

Заготовка в exercises/7-rust-for-data-science/1-rust-from-python/2-strompy/ реализует задуманное на Rust и также содержит синхронную реализацию. Посмотрите код и попробуйте в нём разобраться. Если хотите узнать больше о зависимостях, помогут docs.rs. Обратите внимание, что для struson мы импортируем форк, который поддерживает асинхронную десериализацию.

Чтобы собрать и выполнить тесты из src/lib.rs, запустите cargo test.

Упражнение 7.2.2.B: Синхронный путь ⭐⭐

В ходе следующих упражнений полезно иметь под рукой руководство PyO3 и документацию API PyO3.

Это упражнение посвящено тому, чтобы заставить работать strompy_test.py. Для этого исправьте todo!() в функции exec в src/lib.rs. Не забудьте добавить функцию в экспортируемый модуль!

Если всё сделано правильно, запустите:

$ maturin develop
$ python strompy_test.py

7.2.2.B: Асинхронный путь ⭐⭐⭐

На этот раз заставим работать strompy_test_async.py. Реализуйте feed_bytes и добавьте в тип StrompyJsonReader асинхронный метод, который возвращает PyResult<Option<Vec<Vec<f64>>>> и экспортируется под именем next.

Если всё сделано правильно, запустите:

$ maturin develop
$ python strompy_test_async.py

7.2.2.C: Дополнительные возможности (бонус) ⭐⭐⭐

Сможете ли вы добавить в strompy поддержку других операций из nalgebra?

7.2.2.D: Наведение порядка (бонус) ⭐⭐⭐⭐

Представление векторов как Vec<Vec<f64>> работает, но не слишком хорошо. Сделайте так, чтобы StrompyJsonReader возвращал PyResult<Option<Py<PyList>>>, то есть списки PyList вместо векторов.

Это довольно трудное упражнение, поскольку оно связано с умными указателями PyO3: Py<T>, Bound<'py, T> и токенами GIL: Python.