# Типичные ошибки и как их избежать Сборник реальных проблем, с которыми сталкиваются студенты на этом курсе. Прочитайте перед началом работы — сэкономит часы отладки. ## 1. `multiprocessing` на Windows: `BrokenProcessPool` / бесконечный цикл **Симптом:** при запуске кода с `Pool` или `Process` на Windows процесс перезапускается бесконечно или падает с ошибкой пиккелинга. **Причина:** Windows использует метод запуска `spawn` — каждый дочерний процесс заново импортирует ваш модуль. Если создание воркеров не защищено, оно повторяется в каждом импорте. **Лечение:** весь код создания процессов — только под `if __name__ == "__main__":`. Это правило №1 курса. ```python def main(): with Pool(4) as pool: ... if __name__ == "__main__": main() ``` ## 2. «Мой параллельный код медленнее последовательного» **Причины по частоте:** 1. Накладные расходы (запуск процесса ~10–100 мс, передача данных через pickle) больше, чем выгода, — работа слишком мелкая. 2. GIL: потоки на CPU-bound задаче не ускоряют, а только добавляют переключения. 3. Слишком много частей: 10 000 задач по 1 мс — плохо; 4–8 частей по 100 мс — хорошо. **Что делать:** это не ошибка, а результат для анализа. Опишите его в отчёте — именно это и является целью курса. ## 3. Результат параллельного запуска не совпадает с последовательным **Причины:** - результат зависит от порядка сборки частичных результатов; - несколько воркеров изменяют общую структуру без синхронизации (гонка); - случайные данные без фиксированного seed. **Лечение:** в этом курсе все задачи устроены так, что checksum не зависит от разбиения. Если не совпадает — ищите гонку или неверную сборку. ## 4. Дедлок в producer–consumer **Симптом:** программа висит и не завершается. **Частые причины:** - потребитель ждёт `queue.get()` в бесконечном цикле, а производитель уже закончил — используйте `queue.put(None)` как «маркер конца» или `queue.close()` + `join_thread()`; - `pool.apply()` без закрытия пула; - ожидание события, которое никто не установит. **Отладка:** добавьте print перед/после каждого get/put — сразу видно, кто кого не дождался. ## 5. `asyncio.run()` нельзя вложить **Симптом:** `RuntimeError: asyncio.run() cannot be called from a running event loop`. **Причина:** попытка запустить event loop внутри уже работающего (например, из Jupyter). **Лечение:** один `asyncio.run(main())` на программу, вызывается из обычного синхронного кода. ## 6. Забыли `await` **Симптом:** `RuntimeWarning: coroutine ... was never awaited`, код выполняется мгновенно и ничего не делает. **Причина:** вызов корутины без `await` создаёт объект корутины, но не запускает её. **Лечение:** `await корутина()` — всегда. ## 7. Кириллица «кракозябрами» в консоли Windows ```bat chcp 65001 ``` или запуск через `python -X utf8 файл.py`. В VS Code терминал обычно уже UTF-8. ## 8. `pytest` не находит модуль студента **Причина:** тесты запускаются не из корня курса, или solution.py лежит не там. **Лечение:** запускать `python -m pytest tests/ -k labXX` строго из корня курса; `solution.py` — в папке своей лабораторной. ## 9. Замеры «прыгают» - закройте браузер/IDE-мессенджеры на время замеров; - на ноутбуке подключите питание (троттлинг на батарее режет частоту вдвое); - берите лучшее время из ≥3 повторов (`time_call`); - не замеряйте в отладчике. ## 10. Списывание Код проверяется и на совпадение между собой, и на понимание при защите. Варианты у всех разные (см. `common/варианты.md`) — чужой вариант виден сразу.