Как да обменяте големи двоични данни (~50MB) между външни процеси, които обикновено пишат във файлове в Python

Крайната ми цел е да мога да свържа заедно процеси на командния ред, които работят с файлове, без да докосвам диска. Възможно ли е това? Не мога да използвам stdin/stdout, защото някои от процесите, които трябва да стартирам, приемат само файлове (понякога повече от един) като входни данни. Успях да направя това с помощта на FIFO и Popen с малки файлове в Python, но не и с по-големи файлове (в MB мащаб). Ето фрагмент от код, който използвам, за да тествам тази функционалност.

fifo1 = os.getcwd()+'/fifo1.nii'
fifo2 = os.getcwd()+'/fifo2.nii'

command = 'diff \''+fifo1+'\' \''+fifo2+'\''

os.mkfifo(fifo1)
os.mkfifo(fifo2)

with open('1_brain.nii', 'rb', 0) as r:
    s1 = r.read()
with open('run1.nii', 'rb', 0) as r:
    s2 = r.read()

def write(fifo, s):
    with open(fifo, 'wb', 0) as f:
        f.write(s)

writer1 = Thread(target=write, args=[fifo1, s1])
writer1.start()

writer2 = Thread(target=write, args=[fifo2, s2])
writer2.start()

proc = Popen(shlex.split(command), stdout=PIPE)

try:
    while proc.poll() == None:
        continue
    print proc.communicate()[0]
except:
    if proc.poll() == None:
        proc.kill()
    os.unlink(fifo1)
    os.unlink(fifo2)
    raise

os.unlink(fifo1)
os.unlink(fifo2)

Това работи с малки текстови файлове, но когато го стартирам на големи двоични файлове, получавам грешка за прекъсната тръба в моите нишки за запис, така че изглежда, че краят на четенето (процесът на разлика) се затваря, преди записът да приключи. Накарах процеси за четене на файлове да четат stdin чрез използване на символна връзка към дескриптора на stdin файл, но не мога да използвам stdin, тъй като понякога имам нужда от множество входове. Има ли начин да накарам FIFO да работят или е възможно да създам собствени файлови дескриптори, които работят като stdin за изпращане на данни в процеси? Моля, уведомете ме, ако нещо от това не е ясно! Благодаря.


person Shark    schedule 11.09.2015    source източник
comment
Вижте pdf на трикове за генератор на Python за системни програмисти   -  person Peter Wood    schedule 11.09.2015
comment
(1) 50 MB не са големи за компютър, който може да работи с CPython. Това показва грешка във вашия код (2) Защо четете файловете в паметта само за да ги изхвърлите в именувани канали, вместо да предавате файловете директно на дъщерния процес? Създайте пълен пример за минимален код (използвайте фиктивен скрипт на Python като дъщерен процес) (3) Премахнете фалшивия while proc.poll() == None цикъл, използвайте само proc.communicate() вместо. (4) Несвързано: можете да използвате /dev/fd/N имена на файлове вместо именувани канали   -  person jfs    schedule 11.09.2015
comment
Опитах вариант на кода от предишния коментар с 5GB вход (100 пъти по-голям от вашия случай). Работи добре.   -  person jfs    schedule 12.09.2015
comment
Благодаря за отговора! За да отговоря на въпроса ви, изхвърлям в наименувани канали, защото крайната ми цел е да съединя множество процеси, така че идеята е, че един процес ще се изхвърли в канал, а следващият ще го прочете. Дали файловите дескриптори /dev/fd/ ще действат като тръба, в това отношение ще могат ли да изпълняват поведението, което току-що описах (изхвърляне от един процес, след това четене в следващия)?   -  person Shark    schedule 13.09.2015
comment
@Shark: да, примерът на код от връзката в първия ми коментар демонстрира точно това.   -  person jfs    schedule 15.09.2015