109 lines
5.5 KiB
Markdown
109 lines
5.5 KiB
Markdown
# Типичные ошибки и как их избежать
|
||
|
||
Сборник реальных проблем, с которыми сталкиваются студенты на этом курсе.
|
||
Прочитайте перед началом работы — сэкономит часы отладки.
|
||
|
||
## 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`) — чужой вариант виден сразу. |