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, без последния нов ред.

Изпълнявайки това, бихте очаквали да видите "Running" на всеки ред. Въпреки това, понякога се показва " Работи" или "Работи Работи\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()

Това е така, защото print на Python не е нишка - безопасно. За да избегнете състоянието на състезание между отпечатване на текст и нов ред, пишете директно в stdout, като това:

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 /questions/9338409/ - person CrackerJack9; 18.02.2012
comment
@CrackerJack9 С няколко модификации трябва да можете да свържете всяка многофайлова програма на Python в една. Ако това не е възможно (или програмата е много дълга), качете файловете в gist или pastebin - person phihag; 18.02.2012