Процесс форка Python внутри ноутбука Jupyter

#python #python-3.x #jupyter-notebook #ipython #fork

#python #python-3.x #jupyter-notebook #ipython #форк

Вопрос:

Я запускаю следующий код внутри ноутбука Jupyter:

 import os

print("Start")
pid = os.fork()

if pid == 0:
    print("Child")
    os._exit(os.EX_OK)
else:
    print("Parent")
    
if pid != 0:
    # parent
    pid, status = os.waitpid(pid, 0)
    print("Done")
  

Я получаю следующий вывод «почти» каждый раз:

Дочерний
запуск
родительского
элемента завершен

Как получается, что «Дочерний элемент» печатается перед «запуском»? Почти в 9 из 10 раз я получаю результат, как указано выше. Иногда я нахожу то, что интуитивно ожидается (сначала печатается «Start», затем «Parent» или «Child», а затем, наконец, заканчивается «Done»).

Когда я запускаю один и тот же код непосредственно на консоли, я каждый раз получаю ожидаемый результат:

Запуск
родительского
дочернего
элемента завершен

Почему мы видим это странное поведение в Jupyter Notebook? И как этого избежать?

Ответ №1:

Похоже, что стандартный вывод буферизуется по блокам, а не по строкам. Родительский «Start n» ожидает в выходном буфере. Дочерний элемент «Child n» запускается в своем собственном выходном буфере, но сбрасывается при выходе. Вы могли бы проверить с import sys;print(sys.stdout.isatty()) помощью . Решение состоит в том, чтобы часто очищать

 print("Start", flush=True)
  

или, если у вас есть несколько вещей для печати,

 print("Foo")
print("Bar")
sys.stdout.flush()
  

Комментарии:

1. Ваше решение, безусловно, исправило порядок для меня! Большое спасибо 🙂 Я собираюсь проверить, связана ли эта проблема с печатью.

2. Это будет зависеть от того, как он выполняется. Я не часто использую jupyter, поэтому я не уверен. Но если это сделано через %run , это может быть просто конвейерный подпроцесс, поэтому стандартный вывод будет буферизован по блокам.

Ответ №2:

На данный момент я не знаю способа избежать этого. Возможно, есть параметр, который включен. Вы также можете попробовать добавить ожидание. Перед печатью дочернего или родительского элемента и т. Д. Надеюсь, это немного поможет.

Спите так:

 import time
 
# Wait for 5 seconds
time.sleep(5)
 
# Wait for 300 milliseconds
# .3 can also be used
time.sleep(.300)
  

Я бы предложил подождать от .5 миллисекунд до 1 секунды

Комментарии:

1. Не могли бы вы показать мне, что вы предлагаете, добавив wait? Также не будет ли это слишком произвольным в зависимости от конкретного случая о том, какую задержку мы применяем.

2. Спасибо за ваш ответ. Я надеюсь, что есть какой-то другой способ преодолеть эту проблему, поскольку использование таймеров очень «хакерское». (Тем не менее, если никто другой не сможет предложить более простое решение, я прибегну к этому). Спасибо.