труба Python ограничена 196608 (65536 * 3) с подпроцессом.Popen () - PullRequest
0 голосов
/ 22 декабря 2018

У меня есть эта функция call_external_command Если len (data) <= 196608, это нормально, но если len (data)> 196608, это зависает навсегда.

def call_external_command(command, data):
    try:
        p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
        p.stdin.write(data)
    except:
        return None
    else:
        return p.communicate()[0]

Почему это ограничение?А как обойтись?

Ответы [ 2 ]

0 голосов
/ 23 декабря 2018

Как вы сами узнали, .communicate() справляется с этим.

Причина ваших наблюдений заключается в следующем:

  • Два канала соединяют вашу программу и подпроцесс, а именно:stdin и его стандартный вывод.
  • В зависимости от ОС каждый из этих каналов имеет размер буфера 65536 байт.
  • Кроме того, в зависимости от программы и ее функций он читает 65536 байт какну и выводит некоторые данные.

Итак, если вы пишете 196608 байт, первые 65536 байт отправляются в stdin, читаются программой и (если это, например, cat) выводятсяна стандартный вывод.Вторые 65536 байт помещаются в stdin, читаются программой и пытаются записать в stdout, но там он блокируется, так как stdout заполнен.Третьи 65536 байтов записываются в стандартный ввод.Для каждого лишнего байта пишите блоки, потому что stdin также полон.

Решение такое, как вы пишете: пусть .communicate() обрабатывает все это.Он подготовлен для этой ситуации и обрабатывает его в зависимости от ОС с помощью потоков, опросов или вызовов select.

0 голосов
/ 23 декабря 2018

О, здорово!На самом деле мы должны использовать communicate() вместо stdin.write():

def call_external_command(command, data):
    p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
    return p.communicate(data)[0]
...