I've prototyped a command line application for quick note-taking using Python and argparse. Right now it basically just launches Vim and then shoves the buffer into a SQLite database.
The problem is, loading Python is slow on both of my machines (~2/3GHz Intel Core 2 Duos) and the most basic functionality (printing a help menu on startup) can take over a second. I know my code is fine because Python is perfectly fast and the interactive mode is snappy once Python loads, but I can mimic my annoyance with a simple Hello Word:
$ time python -c "print 'hello world'"
hello world
real 0m0.669s
user 0m0.070s
sys 0m0.041s
Of course, the problem is not unique to Python:
$ time erl -noshell -eval 'io:fwrite("Hello, World!\n"), init:stop().'
Hello, World!
real 0m2.824s
user 0m0.253s
sys 0m0.104s
My question is: How can I speed up the initial execution of a Python application? I want my program to feel like git or wc.
System: I encounter this problem with python2.6 on OS X 10.6.8 and with python2.7 on OS X 10.7.2.
Note: Subsequent executions of python (and erl) are much faster, but I'm already dogfooding this program and I want it to be truly snappy.
Update: I've tried running pypy and find it has similar initial load time to python2.6 and 2.7 on both of my systems (~.5 seconds on initial load), half the performance on subsequent calls compared to python2.6 on OS X 10.6.8 (~.08s for pypy, ~.35s for 2.6), and similar performance on subsequent calls compared to python2.7 on OS X 10.7.2 (~.08s for pypy and python2.7).
Update 2: Output from dr jimbob's suggestion (this seems to trim the initial load time by 2/3) -
$ python -vSEc "print 'hello world'"
# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
import encodings # directory /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings
# /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/__init__.pyc matches /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/__init__.py
import encodings # precompiled from /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/__init__.pyc
# /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/codecs.pyc matches /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/codecs.py
import codecs # precompiled from /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/codecs.pyc
import _codecs # builtin
# /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/aliases.pyc matches /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/aliases.py
import encodings.aliases # precompiled from /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/aliases.pyc
# /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/utf_8.pyc matches /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/utf_8.py
import encodings.utf_8 # precompiled from /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/encodings/utf_8.pyc
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
hello world
# clear __builtin__._
# clear sys.path
# clear sys.argv
# clear sys.ps1
# clear sys.ps2
# clear sys.exitfunc
# clear sys.exc_type
# clear sys.exc_value
# clear sys.exc_traceback
# clear sys.last_type
# clear sys.last_value
# clear sys.last_traceback
# clear sys.path_hooks
# clear sys.path_importer_cache
# clear sys.meta_path
# clear sys.flags
# clear sys.float_info
# restore sys.stdin
# restore sys.stdout
# restore sys.stderr
# cleanup __main__
# cleanup[1] zipimport
# cleanup[1] _codecs
# cleanup[1] signal
# cleanup[1] encodings
# cleanup[1] encodings.utf_8
# cleanup[1] encodings.aliases
# cleanup[1] exceptions
# cleanup[1] _warnings
# cleanup[1] codecs
# cleanup sys
# cleanup __builtin__
# cleanup ints: 3 unfreed ints
# cleanup floats
real 0m0.267s
user 0m0.009s
sys 0m0.043s
解决方案
You can make use of a similar technique used by the infamous "Microsoft Office Quick Start" or the "Java Quick Start" and, IIRC even the "Adobe Fast-something"...
The trick is to try and keep all the libraries of the program in the disk cache, all the time.
You can get it with a simple crontab command, programmed to be run once each hour. The exact details will depend on your system, but should work with something like:
$ crontab -e
0 * * * * python -c 'pass'
Although to me more effective you should write a simple Python script that imports all the modules your program is using and then just ends.