Files
parallel-programming/common/типичные_ошибки.md
2026-10-07 13:06:47 +05:00

109 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Типичные ошибки и как их избежать
Сборник реальных проблем, с которыми сталкиваются студенты на этом курсе.
Прочитайте перед началом работы — сэкономит часы отладки.
## 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`) — чужой вариант виден сразу.