subprocess.Popen не является потокобезопасным?

Я написал этот небольшой тестовый класс, основанный на проблеме Python - закрытой/исправленной, и, похоже, встречается в Python 2.7.1 в Fedora 15.

from subprocess import Popen, PIPE
from threading import Thread

OUTPUT = "asl;dkfhqwiouethnjzxvnhsldfhuyasdhofuiweqamchuisemfawepfhuaipwemhfuaehfclkuehnflw ehfcoiuwehfiuwmhefuiwehfoiuhSfcl hfulh fuiqhuif huiwafh uiahf iUH fhh flkJH fl HASLFuhSAIULFhSUA HFulSAHfOI SUFChiuwqhncriouweycriuowanbyoUIWCryu iWyruawyrouiWYRcoiu YCRoiuNr uyr oUIAWryocIUWRNyc owuroiuNr cuWyrnawueitcnoy U IuiR yiuowaYnorc oWIUAr coiury iuoAW rnuoi asdfsdfd\n"


class X(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        print("Running")
        for i in xrange(10):
            s = Popen(
                "cat /tmp/junk",
                shell=True,
                stdout=PIPE,
                universal_newlines=True
            )
            output = s.communicate()[0]
            if not output == OUTPUT:
                print("Error: %r" % output)


XThreads = set([])

for i in xrange(1000):
    XThreads.add(X())

for x in XThreads:
    x.start()

Просто создайте файл, в данном случае /tmp/junk, с содержимым OUTPUT за вычетом последней новой строки.

Запустив это, вы ожидаете увидеть «Выполняется» в каждой строке. Однако иногда отображается "Выполняется" или "ВыполняетсяВыполняется\n\nВыполняется".

(Удалена ссылка на актуальную проблему, так как это был ложный симптом, благодаря ответу @phihag).

Фактическая проблема: https://stackoverflow.com/questions/9338409/python-subprocess-popen-corrupts-binary-streams


person CrackerJack9    schedule 18.02.2012    source источник


Ответы (1)


Поведение, которое вы видите, не имеет ничего общего с подпроцессом; Я могу воспроизвести его с помощью:

import threading
def run(): print("Running")
for x in [threading.Thread(target=run) for i in range(1000)]:
    x.start()

Это связано с тем, что Python print не является потоком -безопасно. Чтобы избежать состояния гонки между выводом текста и новой строкой, напишите напрямую в стандартный вывод, например:

import threading,sys
def run(): sys.stdout.write("Running\n")
for x in [threading.Thread(target=run) for i in range(1000)]:
    x.start()

Это предполагает, что базовые write вызовы stdout являются потокобезопасными. Это зависит от платформы.

person phihag    schedule 18.02.2012
comment
спасибо, я думаю, что нашел свою проблему, но мне нужно загрузить несколько файлов, чтобы предоставить рабочий пример - не знаю, как это сделать здесь... вы можете помочь? - person CrackerJack9; 18.02.2012
comment
что более интересно, реальная проблема - stackoverflow.com /вопросы/9338409/ - person CrackerJack9; 18.02.2012
comment
@ CrackerJack9 С несколькими изменениями вы сможете объединить любую многофайловую программу Python в одну. Если это невозможно (или программа очень длинная), загрузите файлы в gist или pastebin - person phihag; 18.02.2012