From: Mike Bayer Date: Mon, 5 Jan 2015 00:05:31 +0000 (-0500) Subject: - scale back _Dispatch and _JoinedDispatcher to use a __getitem__ scheme X-Git-Tag: rel_1_0_0b1~131 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b3bf7915b59c9c749d335984e03b386605516d0f;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - scale back _Dispatch and _JoinedDispatcher to use a __getitem__ scheme to start up listener collections; this pulls the overhead off of construction and makes performance much like the descriptor version, while still allowing slots. Fix up some profiles. --- diff --git a/lib/sqlalchemy/event/base.py b/lib/sqlalchemy/event/base.py index 962d850c2a..2d54688863 100644 --- a/lib/sqlalchemy/event/base.py +++ b/lib/sqlalchemy/event/base.py @@ -67,23 +67,35 @@ class _Dispatch(object): # in one ORM edge case, an attribute is added to _Dispatch, # so __dict__ is used in just that case and potentially others. - __slots__ = '_parent', '_instance_cls', '__dict__' + __slots__ = '_parent', '_instance_cls', '__dict__', '_empty_listeners' - _empty_listeners = weakref.WeakKeyDictionary() + _empty_listener_reg = weakref.WeakKeyDictionary() def __init__(self, parent, instance_cls=None): self._parent = parent self._instance_cls = instance_cls if instance_cls: try: - _empty_listeners = self._empty_listeners[instance_cls] + self._empty_listeners = self._empty_listener_reg[instance_cls] except KeyError: - _empty_listeners = self._empty_listeners[instance_cls] = [ - _EmptyListener(ls, instance_cls) - for ls in parent._event_descriptors - ] - for ls in _empty_listeners: - setattr(self, ls.name, ls) + self._empty_listeners = \ + self._empty_listener_reg[instance_cls] = dict( + (ls.name, _EmptyListener(ls, instance_cls)) + for ls in parent._event_descriptors + ) + else: + self._empty_listeners = {} + + def __getattr__(self, name): + # assign EmptyListeners as attributes on demand + # to reduce startup time for new dispatch objects + try: + ls = self._empty_listeners[name] + except KeyError: + raise AttributeError(name) + else: + setattr(self, ls.name, ls) + return ls @property def _event_descriptors(self): @@ -244,9 +256,14 @@ class _JoinedDispatcher(object): self.local = local self.parent = parent self._instance_cls = self.local._instance_cls - for ls in local._event_descriptors: - setattr(self, ls.name, _JoinedListener( - parent, ls.name, ls)) + + def __getattr__(self, name): + # assign _JoinedListeners as attributes on demand + # to reduce startup time for new dispatch objects + ls = getattr(self.local, name) + jl = _JoinedListener(self.parent, ls.name, ls) + setattr(self, ls.name, jl) + return jl @property def _listen(self): diff --git a/test/base/test_events.py b/test/base/test_events.py index 1449bfab0f..8cfbd0180a 100644 --- a/test/base/test_events.py +++ b/test/base/test_events.py @@ -154,16 +154,22 @@ class EventsTest(fixtures.TestBase): t2 = self.Target() t1.dispatch.event_one(5, 6) t2.dispatch.event_one(5, 6) - assert t1.dispatch.event_one in \ - self.Target.dispatch._empty_listeners[self.Target] + is_( + self.Target.dispatch._empty_listener_reg[self.Target]['event_one'], + t1.dispatch.event_one + ) @event.listens_for(t1, "event_one") def listen_two(x, y): pass - assert t1.dispatch.event_one not in \ - self.Target.dispatch._empty_listeners[self.Target] - assert t2.dispatch.event_one in \ - self.Target.dispatch._empty_listeners[self.Target] + is_not_( + self.Target.dispatch._empty_listener_reg[self.Target]['event_one'], + t1.dispatch.event_one + ) + is_( + self.Target.dispatch._empty_listener_reg[self.Target]['event_one'], + t2.dispatch.event_one + ) def test_immutable_methods(self): t1 = self.Target() diff --git a/test/profiles.txt b/test/profiles.txt index c11000e292..507762e652 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -133,8 +133,8 @@ test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_postgresql_psycop test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_cextensions 19280 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_nocextensions 28297 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.3_postgresql_psycopg2_nocextensions 29138 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.3_sqlite_pysqlite_cextensions 32398 -test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.3_sqlite_pysqlite_nocextensions 37327 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.3_sqlite_pysqlite_cextensions 20352 +test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.3_sqlite_pysqlite_nocextensions 29355 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.4_postgresql_psycopg2_cextensions 20135 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.4_postgresql_psycopg2_nocextensions 29138 @@ -147,7 +147,7 @@ test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_postgresql test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_cextensions 27144 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_nocextensions 30149 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.3_postgresql_psycopg2_nocextensions 29068 -test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.3_sqlite_pysqlite_cextensions 32197 +test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.3_sqlite_pysqlite_cextensions 26208 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.3_sqlite_pysqlite_nocextensions 31179 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.4_postgresql_psycopg2_cextensions 26065 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.4_postgresql_psycopg2_nocextensions 29068 @@ -214,11 +214,11 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mysql_mysqldb_cexte test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mysql_mysqldb_nocextensions 117,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_postgresql_psycopg2_cextensions 117,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_postgresql_psycopg2_nocextensions 117,18 -test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_sqlite_pysqlite_cextensions 117,18 -test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_sqlite_pysqlite_nocextensions 117,18 +test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_sqlite_pysqlite_cextensions 91,18 +test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_sqlite_pysqlite_nocextensions 91,18 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_postgresql_psycopg2_nocextensions 122,19 -test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_cextensions 122,19 -test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_nocextensions 122,19 +test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_cextensions 94,19 +test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_nocextensions 94,19 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.4_postgresql_psycopg2_cextensions 122,19 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.4_postgresql_psycopg2_nocextensions 122,19 @@ -351,8 +351,8 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.4_sqlite_pysqlite # TEST: test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation -test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_cextensions 5562,292,3697,11893,1106,1968,2433 -test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_nocextensions 5606,292,3929,13595,1223,2011,2692 +test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_cextensions 5892,292,3697,11893,1106,1968,2433 +test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 2.7_postgresql_psycopg2_nocextensions 5936,292,3929,13595,1223,2011,2692 test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.3_postgresql_psycopg2_cextensions 5497,274,3609,11647,1097,1921,2486 test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.3_postgresql_psycopg2_nocextensions 5519,274,3705,12819,1191,1928,2678 test.aaa_profiling.test_zoomark.ZooMarkTest.test_invocation 3.4_postgresql_psycopg2_cextensions 5497,273,3577,11529,1077,1883,2439