Почему задание печати не выполняется до завершения скрипта Python?

Насколько я понимаю, subprocess.Popen() должен создать новый процесс и не блокирует основной.

Однако следующие сценарии не печатаются, пока не закончатся.

Похоже, что задание на печать добавляется после нажатия кнопки, но по какой-то причине не выполняется напрямую. (По крайней мере, Ubuntu показывает добавленное задание на печать.)

Почему происходит такое поведение?

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import subprocess

lpr =  subprocess.Popen("/usr/bin/lpr",              # on raspbian: /usr/bin/lp
                        stdin=subprocess.PIPE,
                        stdout=subprocess.DEVNULL,   # proposed by user elias
                        close_fds=True)              # proposed by user elias

output = "Username: testuser\n".encode() \
         + "Password: p4ssw0rd\n".encode()

lpr.stdin.write(output)

while True:
    pass

Приведенный выше скрипт ничего не печатает, даже после того, как он был закрыт с помощью Ctrl-C. (Кажется, что задание на печать остается в очереди.)

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import subprocess
import time

lpr =  subprocess.Popen("/usr/bin/lpr",              # on raspbian: /usr/bin/lp
                        stdin=subprocess.PIPE,
                        stdout=subprocess.DEVNULL,   # proposed by user elias 
                        close_fds=True)              # proposed by user elias

output = "Username: testuser\n".encode() \
         + "Password: p4ssw0rd\n".encode()

lpr.stdin.write(output)

time.sleep(20)

Это печатается через 20 секунд (когда скрипт заканчивается).


О среде выполнения:

  • os: ubuntu 18.04 (также встречается на raspbian)
  • питон: 3.6.5
  • принтер: сетевой принтер через CUPS (также происходит при подключении через USB)

РЕШЕНИЕ:

Как видно из комментариев к ответу пользователя elias, такое поведение было вызвано буферизацией.

Проблема решилась закрытием stdin.

lpr.stdin.close()

person AFoeee    schedule 12.09.2018    source источник


Ответы (1)


Я полагаю, что если вы не укажете stdout в вызове Popen, он будет использовать то же, что и родительский процесс, вывод которого, вероятно, принадлежит вашей программе.

Попробуйте добавить stdout=subprocess.DEVNULL (или stdout=subprocess.PIPE, если вы хотите зафиксировать этот вывод).

Из документов:

stdin, stdout и stderr определяют стандартный ввод, стандартный вывод и стандартный дескриптор файла ошибки исполняемой программы соответственно. Допустимые значения: PIPE, DEVNULL, существующий файловый дескриптор (положительное целое число), существующий файловый объект и None. PIPE указывает, что должен быть создан новый канал для дочернего элемента. DEVNULL указывает, что будет использоваться специальный файл os.devnull. При настройках по умолчанию None перенаправление не происходит; дескрипторы дочерних файлов будут унаследованы от родителя.

person Elias Dorneles    schedule 12.09.2018
comment
Спасибо за ваш быстрый ответ. Я добавил параметр, но не уверен, решил ли он проблему. Похоже, что задание на печать добавляется сразу после нажатия кнопки, но не выполняется напрямую. Может быть, это особенность Ubuntu? - person AFoeee; 12.09.2018
comment
Хм, может быть... Если вы все еще хотите убедиться, что он будет работать в фоновом режиме, вы также можете попробовать close_fds=True (увидел это на: stackoverflow.com/a/34459371/149872) - person Elias Dorneles; 12.09.2018
comment
Я добавил параметр, но, к сожалению, поведение все еще происходит. Тем временем я разместил сообщение о проблеме на superuser.com и обновил вопрос. - person AFoeee; 12.09.2018
comment
@AFoeee происходит ли то же самое, если вы запускаете команду в сценарии оболочки вместо сценария Python? что-то вроде: echo -e "Username: testuser\nPassword: p4ssw0rd" | /usr/bin/lpr & - person Elias Dorneles; 13.09.2018
comment
Если вы получаете такое же поведение, проблема определенно не связана с python/urwid. - person Elias Dorneles; 13.09.2018
comment
Команда оболочки печатается немедленно. Я также пересмотрел вопрос, потому что оказалось, что это не имеет отношения к urwid, а обычно возникает при печати на питоне. - person AFoeee; 14.09.2018
comment
Хм, интересно! Может это из-за буферизации? Вы можете попробовать очистить стандартный ввод после записи в него, например lpr.stdin.flush() или, может быть, даже закрыть его lpr.stdin.flush() ? - person Elias Dorneles; 14.09.2018
comment
Хороший звонок, изолирующий проблему, кстати! Мы приближаемся :) - person Elias Dorneles; 14.09.2018
comment
Большое спасибо! lpr.stdin.close() решил проблему. Теперь я чувствую себя немного глупо, что я пытался уничтожить lpr, но не lpr.stdin... - person AFoeee; 14.09.2018
comment
Верно, я хотел написать lpr.stdin.close во второй раз! Не чувствуйте себя глупо, мы только что узнали кое-что! :) - person Elias Dorneles; 14.09.2018