Модуль подпроцесса Python: Как открыть PIPE? - PullRequest
1 голос
/ 05 апреля 2020

У меня есть кусок кода, который нужно запустить node js. Для записи в файл для node js для получения команды я использую следующий код:

def execute(comm):
    file_number = proc.stdin.fileno()
    file = open(file_number, "w+")
    file.write(comm)
    file.close()

execute("""console.log("hi");""")
execute("""console.log("bye");""")

Однако, когда я запускаю команду execute во второй раз, я получаю следующую ошибку:

OSError: [WinError 6] The handle is invalid

Что означает эта ошибка и как ее исправить? Вот полный код:

import subprocess
import threading
import time

class nodePrompt:
    def __init__(self):
        self.proc = subprocess.Popen("node", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
        self.on_out_func = print
        self.on_out_args=[]
        self.on_out_kwargs={}
        self.on_err_func = print
        self.on_err_args=[]
        self.on_err_kwargs={}
        self.on_out_thread=None
        self.on_err_thread=None

    def execute(self, comm):
        file_number = self.proc.stdin.fileno()
        file = open(file_number, "w+")
        file.write(comm)
        file.close()


    def on_out(function, *args, **kwargs):
        self.on_out_func=function
        self.on_out_args=args
        self.on_out_kwargs=kwargs

    def on_err(function, *args, **kwargs):
        self.on_err_func=function
        self.on_err_args=args
        self.on_err_kwargs=kwargs

    def on_out_handle(self):
        for i in iter(self.proc.stdout.readline, ""):
            self.on_out_func(i, *self.on_out_args, **self.on_out_kwargs)

    def start_on_out(self, daemon=False):
        self.on_out_thread=threading.Thread(target=self.on_out_handle)
        self.on_out_thread.setDaemon(daemon)
        self.on_out_thread.start()

    def on_err_handle(self):
        for i in iter(self.proc.stderr.readline, ""):
            self.on_err_func(i, *self.on_err_args, **self.on_err_kwargs)

    def start_on_err(self, daemon=False):
        self.on_err_thread=threading.Thread(target=self.on_err_handle)
        self.on_err_thread.setDaemon(daemon)
        self.on_err_thread.start()

prompt = nodePrompt()
prompt.start_on_out()
prompt.start_on_err()
prompt.execute("console.log(\"HI\");")
time.sleep(1)
prompt.execute("console.log(\"HI\");")

Ответы [ 2 ]

1 голос
/ 05 апреля 2020

Закрытый FIFO не может быть повторно открыт. Все, что вы можете сделать, это не закрывать его, пока вы действительно не закончите. Вместо этого используйте flush(), чтобы обеспечить немедленную запись.

Эта проблема связана с тем, что node.js не запускает код постепенно (или не сбрасывает его вывод) при его вводе и выводе go в конвейеры. Python доказывает, что делает правильно, после исправления кода для работы с self.proc.stdin напрямую.

То есть после изменения execute должно быть определено как:

    def execute(self, comm):
        self.proc.stdin.write(comm)
        self.proc.stdin.flush()

... мы можем отслеживать активность как интерпретатора Python, так и копии node.js, которую он запускает.

К сожалению, node ведет себя не так, как вы этого хотите.

Обратите внимание на отметки времени приведенной ниже трассировки, которая использовала sysdig для отслеживания операций во время выполнения вашей программы:

5178 18:55:37.047606506 4 python (18260) < write res=19 data=console.log("HI");. 
8239 18:55:37.095849210 1 node (18261) < read res=19 data=console.log("HI");. 
8590 18:55:38.048679102 4 python (18260) < write res=19 data=console.log("HI");. 
8595 18:55:38.048710436 4 python (18260) < close res=0 
8597 18:55:38.048742124 1 node (18261) < read res=19 data=console.log("HI");. 
8603 18:55:38.048911687 1 node (18261) < read res=0 data= 
8633 18:55:38.051116830 1 node (18261) < write res=3 data=HI. 
8634 18:55:38.051158022 6 python (18262) < read res=3 data=HI. 
8636 18:55:38.051199286 6 python (18262) < write res=3 data=HI. 
8642 18:55:38.051400907 1 node (18261) < write res=3 data=HI. 
8643 18:55:38.051441455 6 python (18262) < read res=3 data=HI. 
8645 18:55:38.051459654 6 python (18262) < write res=3 data=HI. 

Python записывает первую console.log("HI") , и Node читает его задолго до того, как Node вообще что-либо выводит.

Я бы посоветовал выяснить, запускает ли Node код в том виде, как он получен, когда он поступает из источника, не являющегося TTY, или если он пытается прочитать весь поток до его конца и проанализировать его перед запуском чего-либо.

Рекомендуемый репродуктор

Если вы собираетесь задать этот вопрос для аудитории узла, подумайте над тем, чтобы дать им следующий bash скрипт:

{
  echo 'console.log("HI");'
  sleep 1
  echo 'console.log("HI");'
  sleep 1
  echo "Already sent both commands to node" >&2
} | node

Его ou tput:

Already sent both commands to node
HI
HI

... тогда как можно было бы надеяться, что хотя бы один HI будет напечатан ранее, поскольку после отправки первой команды есть полная задержка в две секунды.

0 голосов
/ 05 апреля 2020

попробуйте добавить file.close_proc() в file.close()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...