Last active
August 29, 2015 14:14
-
-
Save remram44/f85405f6473a326ad4a3 to your computer and use it in GitHub Desktop.
Class generation timing, dynamic vs generated Python
This file contains 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
*.py[co] | |
# Packages | |
*.egg | |
*.egg-info | |
dist | |
build | |
eggs | |
parts | |
bin | |
var | |
sdist | |
develop-eggs | |
.installed.cfg | |
lib | |
lib64 | |
# Installer logs | |
pip-log.txt | |
# Unit test / coverage reports | |
.coverage | |
.tox | |
nosetests.xml | |
# Eclipse PyDev | |
.project | |
.pydevproject | |
# PyCharm | |
.idea | |
# Vagrant | |
.vagrant |
This file contains 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
from __future__ import division, print_function, unicode_literals | |
import os | |
import random | |
import sys | |
import timeit | |
words = ['stitch', 'tense', 'drum', 'prefer', 'lying', 'wiry', 'reject', 'one', | |
'bored', 'interrupt', 'ignorant', 'dramatic', 'material', 'separate', | |
'tremendous', 'furry', 'correct', 'eight', 'geese', 'frame', 'lively', | |
'loose', 'dark', 'wait', 'zippy', 'pets', 'protest', 'violet', 'help'] | |
def main(): | |
if not os.path.isfile('specs.json'): | |
with open('specs.json', 'w') as fp: | |
fp.write('[\n') | |
for i in range(2000): | |
number = random.randint(0, 4) | |
message = ' '.join(random.choice(words) for j in range(3)) | |
name = 'module%d' % (i + 1) | |
fp.write(' {\n' | |
' "name": "%s",\n' | |
' "number": %d,\n' | |
' "message": "%s"\n' | |
' }' % (name, number, message)) | |
if i + 1 != 2000: | |
fp.write(',') | |
fp.write('\n') | |
fp.write(']\n') | |
if len(sys.argv) == 2: | |
if sys.argv[1] == 'static_gen': | |
print(timeit.timeit(setup='import gen_static', | |
stmt='gen_static.generate()', | |
number=1)) | |
return 0 | |
elif sys.argv[1] == 'static': | |
print(timeit.timeit(setup='import gen_static', | |
stmt='gen_static.load()', | |
number=1)) | |
return 0 | |
elif sys.argv[1] == 'dynamic': | |
print(timeit.timeit(setup='import gen_dynamic', | |
stmt='gen_dynamic.load()', | |
number=1)) | |
return 0 | |
print("Usage: class_gen <static_gen|static|dynamic>", file=sys.stderr) | |
sys.exit(1) | |
if __name__ == '__main__': | |
main() |
This file contains 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
from __future__ import division, print_function, unicode_literals | |
import json | |
class BaseClass(object): | |
def update(self): | |
self.compute() | |
def compute(self): | |
raise NotImplementedError | |
def make_compute(nb, s): | |
def specialized_compute(self): | |
for i in range(nb): | |
print(s) | |
def type_(*args): | |
return type(*args) | |
def load(): | |
with open('specs.json', 'rb') as fp: | |
mod_defs = json.load(fp) | |
modules = [] | |
for mod_def in mod_defs: | |
comp = make_compute(mod_def['number'], mod_def['message']) | |
cl = type_(mod_def['name'].encode('ascii'), | |
(BaseClass,), | |
{'compute': comp}) | |
modules.append(cl) | |
assert len(modules) == 2000 |
This file contains 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
from __future__ import division, print_function, unicode_literals | |
from jinja2 import Environment, FileSystemLoader | |
import json | |
class BaseClass(object): | |
def update(self): | |
self.compute() | |
def compute(self): | |
raise NotImplementedError | |
def generate(): | |
env = Environment(loader=FileSystemLoader('.')) | |
template = env.get_template('mod_template.py.jinja2') | |
with open('_generated_modules.py', 'w') as fout: | |
with open('specs.json', 'rb') as fp: | |
mod_defs = json.load(fp) | |
names = [] | |
for mod_def in mod_defs: | |
fout.write(template.render(name=mod_def['name'], | |
number=mod_def['number'], | |
message=repr(mod_def['message']))) | |
fout.write('\n\n\n') | |
names.append(mod_def['name']) | |
fout.write('modules = [\n') | |
for name in names: | |
fout.write(' %s,\n' % name) | |
fout.write(']\n') | |
def load(): | |
from _generated_modules import modules | |
assert len(modules) == 2000 |
This file contains 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
class {{ name }}({{ base_name }}): | |
def compute(self): | |
for i in range({{ number }}): | |
print({{ message }}) |
Obviously, this was because the module is loaded only once.
New version (67c52e9), same machine:
>python -B class_gen.py static_gen
0.0472962108979
>python -B class_gen.py static
0.0881224513533
>python -B class_gen.py dynamic
0.0346671535893
The dynamic version is faster here, with type() calls using most of the time:
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Initial revision (0bf42acc), timings on Windows 7, Python 2.7.9 x86:
Very surprising.