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

5.5 KiB
Raw Permalink Blame History

Типичные ошибки и как их избежать

Сборник реальных проблем, с которыми сталкиваются студенты на этом курсе. Прочитайте перед началом работы — сэкономит часы отладки.

1. multiprocessing на Windows: BrokenProcessPool / бесконечный цикл

Симптом: при запуске кода с Pool или Process на Windows процесс перезапускается бесконечно или падает с ошибкой пиккелинга.

Причина: Windows использует метод запуска spawn — каждый дочерний процесс заново импортирует ваш модуль. Если создание воркеров не защищено, оно повторяется в каждом импорте.

Лечение: весь код создания процессов — только под if __name__ == "__main__":. Это правило №1 курса.

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

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) — чужой вариант виден сразу.