Как передать файловые дескрипторы от родителя к дочернему в python?

Я использую многопроцессорный модуль и использую пулы для запуска нескольких рабочих. Но файловые дескрипторы, открытые в родительском процессе, закрыты в рабочих процессах. Я хочу, чтобы они были открыты..! Есть ли способ передать файловые дескрипторы для совместного использования родительским и дочерним элементами?


person kumar    schedule 07.06.2010    source источник
comment
Как уже упоминалось, вам нужно будет использовать функции, специфичные для ОС. Какие платформы вы заинтересованы в поддержке?   -  person Rakis    schedule 07.06.2010
comment
Мне нужно поддерживать Windows и Linux, поэтому я не хочу использовать какие-либо специфические функции ОС. В Linux дескрипторы файлов являются общими по умолчанию, и в Windows также есть возможность совместно использовать дескрипторы файлов во время CreateProcess()... Я не знаю, почему многопроцессорные модули не имеют дополнительных параметров для совместного использования дескрипторов файлов.   -  person kumar    schedule 07.06.2010
comment
Поскольку Windows и Linux отличаются семантикой передачи дескрипторов файлов, вам, вероятно, придется использовать специфические функции ОС. Однако здесь нет проблем, легко отличить sys.platform и просто вызвать специфичную для ОС функцию, чтобы она работала для этой функции ОС. Я предлагаю прочитать код многопроцессорного модуля, чтобы увидеть, есть ли простой обходной путь.   -  person Rakis    schedule 07.06.2010
comment
Не могли бы вы объяснить, как вы поняли, что они закрыты? Из того, что я прочитал, передача файловых дескрипторов между процессами просто не работает (я не нашел более близкого объяснения), откуда вы знаете, что дескриптор закрыт и, например, не прошел или еще что? Спасибо   -  person Wakan Tanka    schedule 07.09.2015


Ответы (4)


Я не знаю способа поделиться файловыми дескрипторами между процессами. Если способ существует, он, скорее всего, зависит от ОС.

Я предполагаю, что вам нужно обмениваться данными на другом уровне.

person Mattias Nilsson    schedule 07.06.2010
comment
Согласованный. Однако есть способы, специфичные для ОС. - person unbeli; 07.06.2010
comment
Да, я знаю, что fork(), например, будет дублировать файловые дескрипторы, но есть ли простой способ сделать это после запуска процессов? - person Mattias Nilsson; 07.06.2010
comment
Ага: stackoverflow.com/questions/909064/ - person Rakis; 07.06.2010
comment
Круто, я не знал об этом. - person Mattias Nilsson; 08.06.2010
comment
multiprocessing сам имеет функции, которые обрабатывают детали ОС, см. здесь. - person Chris Hunt; 05.01.2019

В Python 2 и Python 3 функции для отправки и получения файловых дескрипторов находятся в модуле multiprocessing.reduction.

Пример кода (Python 2 и Python 3):

import multiprocessing
import os

# Before fork
child_pipe, parent_pipe = multiprocessing.Pipe(duplex=True)

child_pid = os.fork()

if child_pid:
    # Inside parent process
    import multiprocessing.reduction
    import socket
    # has socket_to_pass socket object which want to pass to the child
    socket_to_pass = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
    socket_to_pass.connect("/dev/log")
    # child_pid argument to send_handle() can be arbitrary on Unix,
    # on Windows it has to be child PID
    multiprocessing.reduction.send_handle(parent_pipe, socket_to_pass.fileno(), child_pid)
    socket_to_pass.send("hello from the parent process\n".encode())
else:
    # Inside child process
    import multiprocessing.reduction
    import socket
    import os
    fd = multiprocessing.reduction.recv_handle(child_pipe)
    # rebuild the socket object from fd
    received_socket = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
    # socket.fromfd() duplicates fd, so we can close the received one
    os.close(fd)
    # and now you can communicate using the received socket
    received_socket.send("hello from the child process\n".encode())
person Piotr Jurkiewicz    schedule 31.12.2014
comment
send_handle и recv_handle также существуют в Python 2, как я упоминал в своем ответе здесь, нет необходимости различать их. Кроме того, я бы не стал использовать отправку сокета в качестве примера, поскольку multiprocessing регистрирует socket.socket с помощью своего пользовательского Pickler - объект socket.socket может быть отправлен через Connection напрямую без какого-либо кода выше, но если оставить как есть, кто-то может скопировать его в свой собственная кодовая база. - person Chris Hunt; 05.01.2019
comment
Хорошо, я вижу, что он также был портирован на Python 2. Что касается отправки socket.socket без дополнительного кода, похоже, он не работает с произвольными каналами/сокетами, а только с теми, которые созданы с помощью всего механизма multiprocessing.Manager. - person Piotr Jurkiewicz; 05.01.2019

Существует также ответвление multiprocessing под названием multiprocess, которое заменяет pickle на dill. dill может обрабатывать файловые дескрипторы и, таким образом, multiprocess может легко передавать их между процессами.

>>> f = open('test.txt', 'w')
>>> _ = map(f.write, 'hello world')
>>> f.close()
>>> import multiprocess as mp
>>> p = mp.Pool()
>>> f = open('test.txt', 'r')
>>> p.apply(lambda x:x, f)
'hello world'
>>> f.read()
'hello world'
>>> f.close()
person Mike McKerns    schedule 01.04.2016
comment
@ user765443: может быть, у вас плохая установка multiprocess? вы работаете в Windows и у вас нет компилятора C? - person Mike McKerns; 07.06.2018

Сам multiprocessing имеет вспомогательные методы для передачи дескрипторов файлов между процессами на платформах Windows и Unix, которые поддерживают отправку дескрипторов файлов через сокеты домена Unix в multiprocessing.reduction: send_handle и recv_handle. Они не задокументированы, но находятся в __all__ модуля, поэтому можно с уверенностью предположить, что они являются частью общедоступного API. Судя по источнику, они были доступны как минимум с версий 2.6+ и 3.3+.

Все платформы имеют одинаковый интерфейс:

  • send_handle(conn, handle, destination_pid)
  • recv_handle(conn)

Где:

  • conn (multiprocessing.Connection): соединение, по которому отправить дескриптор файла
  • handle (int): целое число, относящееся к файловому дескриптору/дескриптору
  • destination_pid (int): целочисленный pid процесса, который получает файловый дескриптор — в настоящее время используется только в Windows.
person Chris Hunt    schedule 04.01.2019