Порядок вывода при использовании ThreadPoolExecutor и as_completed

Порядок вывода при использовании ThreadPoolExecutor и as_completed

@python_quiz

Разберем этот квиз

Код для анализа:

python

Кратко о том, что происходит

  • ex.submit(print, "A") ставит задачу в пул потоков: в одном из рабочих потоков будет выполнен print("A").
  • as_completed принимает список будущих результатов (futures) и возвращает итератор, который выдаёт каждый future по мере его завершения.
  • Цикл for ждёт, пока будущая задача не завершится, и только затем выполняет тело цикла — print("B").

Почему сначала печатается "A", а затем "B"

  • Задача (в рабочем потоке) выполняет print("A") и завершает future.
  • as_completed не вернёт этот future до завершения задачи, то есть до фактического выполнения print("A").
  • После того как future помечен как завершённый, итерация продолжается, и основной поток печатает "B".

Следствие: в этом коде вывод всегда будет выглядеть как

Анализ вариантов ответов

  • "Выведет только 'A'": неверно — после того как as_completed отдаст завершённую задачу, в теле цикла явно вызывается print("B"), поэтому B будет напечатано.
  • "Выведет только 'B'": неверно — печать "A" выполняется в рабочем потоке до того, как future считается завершённым и возвращается из as_completed.
  • "Всегда выведет сначала 'A', затем 'B'": соответствует описанной семантике as_completed и submit — сначала выполняется задача (печать "A"), затем в основном потоке печатается "B".
  • "Порядок 'A' и 'B' не гарантирован": не применимо в данном конкретном коде с одним future, потому что как минимум полагаясь на поведение as_completed порядок детерминирован.

Тонкости и исключения

  • Буферизация вывода: если stdout перенаправлён в файл или используется нестандартный буфер, порядок видимого вывода может выглядеть неожиданно. В таких случаях можно явно форсировать flush:
python
  • Если бы в iterable передавалось несколько futures, порядок получения их в as_completed соответствовал бы порядку завершения задач и мог быть не детерминированным относительно друг друга.
  • Если вместо as_completed использовать немедленно возвращающуюся конструкцию или не ждать завершения future, тогда результат мог бы измениться.

Пример для сравнения (несколько задач)

python

В этом примере порядок между 'A' и 'B' зависит от задержек: as_completed вернёт сначала тот future, который завершится раньше.

Вывод

  • В исходном фрагменте с одной задачей и использованием as_completed вывод будет детерминирован: сначала выполняется задача в рабочем потоке и печатается "A", затем в основном потоке печатается "B".
  • При работе с несколькими futures порядок их обработки определяется моментом завершения каждой задачи; для надёжного контроля порядка следует явно синхронизировать выполнение.

Report Page