Прежде всего, общая проблема, которую я решаю, немного сложнее, чем я показываю здесь, поэтому, пожалуйста, не говорите мне «использовать потоки с блокировкой», поскольку это не решило бы мою реальную ситуацию без честного, ЧЕСТНОГО бит переписывания и рефакторинга.
У меня есть несколько приложений, которые я не могу изменить, которые берут данные из stdin и выкачивают их на stdout после выполнения своей магии. Моя задача - связать несколько таких программ Проблема в том, что иногда они задыхаются, и поэтому мне нужно отслеживать их прогресс, который выводится на STDERR.
pA = subprocess.Popen(CommandA, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# ... some more processes make up the chain, but that is irrelevant to the problem
pB = subprocess.Popen(CommandB, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=pA.stdout )
Теперь, чтение напрямую через pA.stdout.readline () и pB.stdout.readline () или обычные функции read () является проблемой блокировки. Поскольку разные приложения выводят данные с разной скоростью и в разных форматах, блокировка невозможна. (И, как я писал выше, многопоточность - это не вариант, если, конечно, в крайнем случае.) pA.communicate()
безопасна для тупиков, но поскольку мне нужна живая информация, это тоже не вариант.
Таким образом, Google привел меня к этому асинхронному фрагменту подпроцесса в ActiveState.
Сначала все хорошо, пока я не осуществлю это. Сравнивая вывод cmd.exe pA.exe | pB.exe
, игнорируя тот факт, что оба вывода выводятся в одно и то же окно, создавая беспорядок, я вижу очень мгновенные обновления. Однако я реализую то же самое, используя приведенный выше фрагмент и объявленную там функцию read_some()
, и для уведомления об обновлениях одного канала требуется более 10 секунд. Но когда он это делает, у него есть обновления, ведущие к 40% прогрессу, например.
Таким образом, я провожу еще несколько исследований и вижу многочисленные темы, касающиеся PeekNamedPipe, анонимных дескрипторов и возврата 0 байтов, даже если в канале есть информация. Поскольку этот предмет оказался вне моей компетенции для исправления или кодирования, я приехал в Stack Overflow, чтобы найти руководство. :)
Моя платформа - W7 64-битная с Python 2.6, приложения 32-битные на случай, если это имеет значение, и совместимость с Unix не является проблемой. Я даже могу иметь дело с полным решением ctypes или pywin32, которое полностью подрывает подпроцесс, если это единственное решение, при условии, что я могу читать из каждого канала stderr асинхронно с немедленной производительностью и без блокировок. :)