Pythonでファイルディスクリプタをサブプロセスに渡す

Pythonのsubprocessモジュールでサブプロセスを実行するときに、親プロセス側で開いたファイルのファイルディスクリプタを渡す方法。

subprocess.Popenのpass_fds引数を指定すると、指定したファイルディスクリプタは閉じられないようだ。

試したPythonのバージョンは3.5。

コード

send_fd.py:

import sys
import subprocess

# ファイルを開く(readで全部読まれるのを避けるのでバッファをOFFにしとく)
input_file = open('spam.txt', 'rb', buffering=0)
# ファイルディスクリプタを取得
fd = input_file.fileno()
# 5バイト読む
print('send_fd: ', input_file.read(5))
# receive_fd.pyに引数でFDを渡して子プロセスとして実行
process = subprocess.Popen(
    [sys.executable, 'receive_fd.py', str(fd)],
    pass_fds=[fd])
# プロセスが終了するまで待つ
process.wait()
# ファイルを閉じる
input_file.close()
print('end')

receive_fd.py:

import os
import sys

# 引数で渡されたFDを取得
fd = int(sys.argv[1])
# FDからファイルオブジェクトを作る
input_file = os.fdopen(fd, 'rb')
# 最後まで読み込んで表示
print('receive_fd: ', input_file.read())
# ファイルを閉じる
input_file.close()

spam.txt:

Hello World!

実行結果

tokibito@ubuntu:~/sandbox$ python3.5 send_fd.py
send_fd:  b'Hello'
receive_fd:  b' World!\n'
end

親プロセス側で5バイト読んで、子プロセス側で残りを読んでいる。

参考