Почему задание на печать не выполняется до тех пор, пока скрипт 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 (также встречается на распбиане)
  • питон: 3.6.5
  • принтер: сетевой принтер через CUPS (также происходит при подключении через USB)

РЕШЕНИЕ:

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

Проблема была решена закрытием стандартного ввода.

lpr.stdin.close()

1 ответ

Решение

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

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

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

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

Другие вопросы по тегам