Created
March 30, 2019 08:16
-
-
Save nakamuray/1eebc14c62cf50edf5d26867ef840ef6 to your computer and use it in GitHub Desktop.
事前起動させておいた python process からの fork により、 python アプリケーションの起動高速化をしてみるテスト
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import array | |
import json | |
import os | |
import socket | |
import sys | |
SOCKET_PATH = '/tmp/pyd.sock' | |
sock = socket.socket(socket.AF_UNIX) | |
sock.connect(SOCKET_PATH) | |
data = { | |
'argv': sys.argv[1:], | |
'env': dict(os.environ), | |
'cwd': os.getcwd(), | |
} | |
sock.sendmsg([json.dumps(data).encode('utf-8')], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array('i', [0, 1, 2]))]) | |
# TODO: signal | |
code = sock.recv(4096) | |
sys.exit(int(code)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import array | |
import json | |
import os | |
import socket | |
import sys | |
SOCKET_PATH = '/tmp/pyd.sock' | |
PRELOAD_MODULES = [ | |
'IPython', | |
] | |
for m in PRELOAD_MODULES: | |
__import__(m) | |
sock = socket.socket(socket.AF_UNIX) | |
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
sock.bind(SOCKET_PATH) | |
sock.listen() | |
while True: | |
print('daemon listening') | |
client, addr = sock.accept() | |
pid = os.fork() | |
if pid: | |
# parent | |
client.close() | |
# TODO: wait child to release zombies | |
continue | |
# child | |
sock.close() | |
pid2 = os.fork() | |
if pid2: | |
# new parent | |
# wait child and send status code to client | |
(_p, code) = os.waitpid(pid2, 0) | |
assert _p > 0 | |
assert os.WIFEXITED(code) | |
code = os.WEXITSTATUS(code) | |
client.sendall(str(code).encode('utf-8')) | |
client.close() | |
else: | |
# new child | |
# setup environment and run code | |
# receive fds from socket | |
fds = array.array('i') | |
# XXX: waht values are correct to use as these? | |
maxfds = 256 | |
msglen = 4096 | |
msg, ancdata, flags, addr = client.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) | |
print('msg', msg) | |
print('ancdata', repr(ancdata)) | |
for cmsg_leve, cmsg_type, cmsg_data in ancdata: | |
if (cmsg_leve == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): | |
fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) | |
else: | |
print(repr(cmsg_data)) | |
data = json.loads(msg) | |
sys.argv = data['argv'] | |
os.environ.clear() | |
for k, v in data['env'].items(): | |
os.environ[k] = v | |
os.chdir(data['cwd']) | |
print(fds) | |
for i in range(3): | |
os.dup2(fds[i], i) | |
os.close(fds[i]) | |
client.close() | |
exec(open(sys.argv[0]).read()) | |
sys.exit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
python アプリケーションの起動高速化をするのに、事前に python process を起動して、必要なモジュールの読み込みまでを済ませておき、実際のアプリケーションはそこから fork する形で起動・実行すれば、モジュール読み込み時間が省けて速くなるのでは?と思い立ったので実験。
とりあえずのテストとして、手元の環境だと起動に微妙に時間がかかる ipython (
IPython
モジュール) を使う。事前に
としてデーモン側を起動・モジュール読み込みをさせておく。
普通に実行:
事前起動した process を使って実行:
... ということで、 ipython でヘルプを出すまでの時間は 0.725s → 0.263s となり、ひとまず高速化は出来たっぽい。