mirror of
https://github.com/python/cpython.git
synced 2025-12-09 02:35:14 +00:00
svn+ssh://pythondev@svn.python.org/python/trunk ........ r53012 | walter.doerwald | 2006-12-12 22:55:31 +0100 (Tue, 12 Dec 2006) | 2 lines Fix typo. ........ r53023 | brett.cannon | 2006-12-13 23:31:37 +0100 (Wed, 13 Dec 2006) | 2 lines Remove an unneeded import of 'warnings'. ........ r53025 | brett.cannon | 2006-12-14 00:02:38 +0100 (Thu, 14 Dec 2006) | 2 lines Remove unneeded imports of 'warnings'. ........ r53026 | brett.cannon | 2006-12-14 00:09:53 +0100 (Thu, 14 Dec 2006) | 4 lines Add test.test_support.guard_warnings_filter . This function returns a context manager that protects warnings.filter from being modified once the context is exited. ........ r53029 | george.yoshida | 2006-12-14 03:22:44 +0100 (Thu, 14 Dec 2006) | 2 lines Note that guard_warnings_filter was added in 2.6 ........ r53031 | vinay.sajip | 2006-12-14 09:53:55 +0100 (Thu, 14 Dec 2006) | 1 line Added news on recent changes to logging ........ r53032 | andrew.kuchling | 2006-12-14 19:57:53 +0100 (Thu, 14 Dec 2006) | 1 line [Patch #1599256 from David Watson] check that os.fsync is available before using it ........ r53042 | kurt.kaiser | 2006-12-15 06:13:11 +0100 (Fri, 15 Dec 2006) | 6 lines 1. Avoid hang when encountering a duplicate in a completion list. Bug 1571112. 2. Duplicate some old entries from Python's NEWS to IDLE's NEWS.txt M AutoCompleteWindow.py M NEWS.txt ........ r53048 | andrew.kuchling | 2006-12-18 18:12:31 +0100 (Mon, 18 Dec 2006) | 1 line [Bug #1618083] Add missing word; make a few grammar fixes ........ r53050 | andrew.kuchling | 2006-12-18 18:16:05 +0100 (Mon, 18 Dec 2006) | 1 line Bump version ........ r53051 | andrew.kuchling | 2006-12-18 18:22:07 +0100 (Mon, 18 Dec 2006) | 1 line [Bug #1616726] Fix description of generator.close(); if you raise some random exception, the exception is raised and doesn't trigger a RuntimeError ........ r53052 | andrew.kuchling | 2006-12-18 18:38:14 +0100 (Mon, 18 Dec 2006) | 1 line Describe new methods in Queue module ........ r53053 | andrew.kuchling | 2006-12-18 20:22:24 +0100 (Mon, 18 Dec 2006) | 1 line [Patch #1615868 by Lars Gustaebel] Use Py_off_t to fix BZ2File.seek() for offsets > 2Gb ........ r53057 | andrew.kuchling | 2006-12-18 22:29:07 +0100 (Mon, 18 Dec 2006) | 1 line Fix markup ........ r53063 | thomas.wouters | 2006-12-19 09:17:50 +0100 (Tue, 19 Dec 2006) | 5 lines Make sre's SubPattern objects accept slice objects like it already accepts simple slices. ........ r53065 | andrew.kuchling | 2006-12-19 15:13:05 +0100 (Tue, 19 Dec 2006) | 6 lines [Patch #1618455 by Ben Maurer] Improve speed of HMAC by using str.translate() instead of a more general XOR that has to construct a list. Slightly modified from Maurer's patch: the _strxor() function is no longer necessary at all. ........ r53066 | andrew.kuchling | 2006-12-19 15:28:23 +0100 (Tue, 19 Dec 2006) | 9 lines [Bug #1613651] Document socket.recv_into, socket.recvfrom_into Also, the text for recvfrom told you to read recv() for an explanation of the 'flags' argument, but recv() just pointed you at the man page. Copied the man-page text to recvfrom(), recvfrom_into, recv_into to avoid the pointless redirection. I don't have LaTeX on this machine; hope my markup is OK. ........ r53067 | andrew.kuchling | 2006-12-19 15:29:04 +0100 (Tue, 19 Dec 2006) | 1 line Comment typo ........ r53068 | andrew.kuchling | 2006-12-19 16:11:41 +0100 (Tue, 19 Dec 2006) | 1 line [Patch #1617413 from Dug Song] Fix HTTP Basic authentication via HTTPS ........ r53071 | andrew.kuchling | 2006-12-19 16:18:12 +0100 (Tue, 19 Dec 2006) | 1 line [Patch #1600491 from Jim Jewett] Describe how to build help files on Windows ........ r53073 | andrew.kuchling | 2006-12-19 16:43:10 +0100 (Tue, 19 Dec 2006) | 6 lines [Patch #1587139 by kxroberto] Protect lock acquisition/release with try...finally to ensure the lock is always released. This could use the 'with' statement, but the patch uses 'finally'. 2.5 backport candidate. ........ r53074 | vinay.sajip | 2006-12-19 19:29:11 +0100 (Tue, 19 Dec 2006) | 1 line Updated documentation for findCaller() to indicate that a 3-tuple is now returned, rather than a 2-tuple. ........ r53090 | georg.brandl | 2006-12-19 23:06:46 +0100 (Tue, 19 Dec 2006) | 3 lines Patch #1484695: The tarfile module now raises a HeaderError exception if a buffer given to frombuf() is invalid. ........ r53099 | raymond.hettinger | 2006-12-20 07:42:06 +0100 (Wed, 20 Dec 2006) | 5 lines Bug #1590891: random.randrange don't return correct value for big number Needs to be backported. ........ r53106 | georg.brandl | 2006-12-20 12:55:16 +0100 (Wed, 20 Dec 2006) | 3 lines Testcase for patch #1484695. ........ r53110 | andrew.kuchling | 2006-12-20 20:48:20 +0100 (Wed, 20 Dec 2006) | 17 lines [Apply length-checking.diff from bug #1599254] Add length checking to single-file mailbox formats: before doing a flush() on a mailbox, seek to the end and verify its length is unchanged, raising ExternalClashError if the file's length has changed. This fix avoids potential data loss if some other process appends to the mailbox file after the table of contents has been generated; instead of overwriting the modified file, you'll get the exception. I also noticed that the self._lookup() call in self.flush() wasn't necessary (everything that sets self._pending to True also calls self.lookup()), and replaced it by an assertion. 2.5 backport candidate. ........ r53112 | andrew.kuchling | 2006-12-20 20:57:10 +0100 (Wed, 20 Dec 2006) | 1 line [Bug #1619674] Make sum() use the term iterable, not sequence ........ r53113 | andrew.kuchling | 2006-12-20 20:58:11 +0100 (Wed, 20 Dec 2006) | 1 line Two grammar fixes ........ r53115 | andrew.kuchling | 2006-12-20 21:11:12 +0100 (Wed, 20 Dec 2006) | 5 lines Some other built-in functions are described with 'sequence' arguments that should really be 'iterable'; this commit changes them. Did I miss any? Did I introduce any errors? ........ r53117 | andrew.kuchling | 2006-12-20 21:20:42 +0100 (Wed, 20 Dec 2006) | 1 line [Bug #1619680] in_dll() arguments are documented in the wrong order ........ r53120 | neal.norwitz | 2006-12-21 05:38:00 +0100 (Thu, 21 Dec 2006) | 1 line Lars asked for permission on on python-dev for work on tarfile.py ........ r53125 | andrew.kuchling | 2006-12-21 14:40:29 +0100 (Thu, 21 Dec 2006) | 1 line Mention the os.SEEK_* constants ........ r53129 | walter.doerwald | 2006-12-21 19:06:30 +0100 (Thu, 21 Dec 2006) | 2 lines Fix typo. ........ r53131 | thomas.heller | 2006-12-21 19:30:56 +0100 (Thu, 21 Dec 2006) | 3 lines Fix wrong markup of an argument in a method signature. Will backport. ........ r53137 | andrew.kuchling | 2006-12-22 01:50:56 +0100 (Fri, 22 Dec 2006) | 1 line Typo fix ........ r53139 | andrew.kuchling | 2006-12-22 14:25:02 +0100 (Fri, 22 Dec 2006) | 1 line [Bug #737202; fix from Titus Brown] Make CGIHTTPServer work for scripts in sub-directories ........ r53141 | andrew.kuchling | 2006-12-22 16:04:45 +0100 (Fri, 22 Dec 2006) | 6 lines [Bug #802128] Make the mode argument of dumbdbm actually work the way it's described, and add a test for it. 2.5 bugfix candidate, maybe; arguably this patch changes the API of dumbdbm and shouldn't be added in a point-release. ........ r53142 | andrew.kuchling | 2006-12-22 16:16:58 +0100 (Fri, 22 Dec 2006) | 6 lines [Bug #802128 continued] Modify mode depending on the process umask. Is there really no other way to read the umask than to set it? Hope this works on Windows... ........ r53145 | andrew.kuchling | 2006-12-22 17:43:26 +0100 (Fri, 22 Dec 2006) | 1 line [Bug #776202] Apply Walter Doerwald's patch to use text mode for encoded files ........ r53146 | andrew.kuchling | 2006-12-22 19:41:42 +0100 (Fri, 22 Dec 2006) | 9 lines [Patch #783050 from Patrick Lynch] The emulation of forkpty() is incorrect; the master should close the slave fd. Added a test to test_pty.py that reads from the master_fd after doing a pty.fork(); without the fix it hangs forever instead of raising an exception. (<crossing fingers for the buildbots>) 2.5 backport candidate. ........ r53147 | andrew.kuchling | 2006-12-22 20:06:16 +0100 (Fri, 22 Dec 2006) | 1 line [Patch #827559 from Chris Gonnerman] Make SimpleHTTPServer redirect when a directory URL is missing the trailing slash; this lets relative links work. ........ r53149 | andrew.kuchling | 2006-12-22 20:21:27 +0100 (Fri, 22 Dec 2006) | 1 line Darn; this test works when you run test_pty.py directly, but fails when regrtest runs it (the os.read() raises os.error). I can't figure out the cause, so am commenting out the test. ........ r53150 | andrew.kuchling | 2006-12-22 22:48:19 +0100 (Fri, 22 Dec 2006) | 1 line Frak; this test also fails ........ r53153 | lars.gustaebel | 2006-12-23 17:40:13 +0100 (Sat, 23 Dec 2006) | 5 lines Patch #1230446: tarfile.py: fix ExFileObject so that read() and tell() work correctly together with readline(). Will backport to 2.5. ........ r53155 | lars.gustaebel | 2006-12-23 18:57:23 +0100 (Sat, 23 Dec 2006) | 5 lines Patch #1262036: Prevent TarFiles from being added to themselves under certain conditions. Will backport to 2.5. ........ r53159 | andrew.kuchling | 2006-12-27 04:25:31 +0100 (Wed, 27 Dec 2006) | 4 lines [Part of patch #1182394] Move the HMAC blocksize to be a class-level constant; this allows changing it in a subclass. To accommodate this, copy() now uses __class__. Also add some text to a comment. ........ r53160 | andrew.kuchling | 2006-12-27 04:31:24 +0100 (Wed, 27 Dec 2006) | 1 line [Rest of patch #1182394] Add ._current() method so that we can use the written-in-C .hexdigest() method ........ r53161 | lars.gustaebel | 2006-12-27 11:30:46 +0100 (Wed, 27 Dec 2006) | 4 lines Patch #1504073: Fix tarfile.open() for mode "r" with a fileobj argument. Will backport to 2.5. ........ r53165 | neal.norwitz | 2006-12-28 05:39:20 +0100 (Thu, 28 Dec 2006) | 1 line Remove a stray (old) macro name left around (I guess) ........ r53188 | neal.norwitz | 2006-12-29 04:01:53 +0100 (Fri, 29 Dec 2006) | 1 line SF bug #1623890, fix argument name in docstring ........ r53200 | raymond.hettinger | 2006-12-30 05:01:17 +0100 (Sat, 30 Dec 2006) | 1 line For sets with cyclical reprs, emit an ellipsis instead of infinitely recursing. ........ r53232 | brett.cannon | 2007-01-04 01:23:49 +0100 (Thu, 04 Jan 2007) | 3 lines Add EnvironmentVarGuard to test.test_support. Provides a context manager to temporarily set or unset environment variables. ........ r53235 | neal.norwitz | 2007-01-04 07:25:31 +0100 (Thu, 04 Jan 2007) | 1 line SF #1627373, fix typo in CarbonEvt. ........ r53244 | raymond.hettinger | 2007-01-04 18:53:34 +0100 (Thu, 04 Jan 2007) | 1 line Fix stability of heapq's nlargest() and nsmallest(). ........ r53249 | martin.v.loewis | 2007-01-04 22:06:12 +0100 (Thu, 04 Jan 2007) | 3 lines Bug #1566280: Explicitly invoke threading._shutdown from Py_Main, to avoid relying on atexit. Will backport to 2.5. ........ r53252 | gregory.p.smith | 2007-01-05 02:59:42 +0100 (Fri, 05 Jan 2007) | 3 lines Support linking of the bsddb module against BerkeleyDB 4.5.x (will backport to 2.5) ........ r53253 | gregory.p.smith | 2007-01-05 03:06:17 +0100 (Fri, 05 Jan 2007) | 2 lines bump module version to match supported berkeleydb version ........ r53255 | neal.norwitz | 2007-01-05 06:25:22 +0100 (Fri, 05 Jan 2007) | 6 lines Prevent crash on shutdown which can occur if we are finalizing and the module dict has been cleared already and some object raises a warning (like in a __del__). Will backport. ........ r53258 | gregory.p.smith | 2007-01-05 08:21:35 +0100 (Fri, 05 Jan 2007) | 2 lines typo fix ........ r53260 | neal.norwitz | 2007-01-05 09:06:43 +0100 (Fri, 05 Jan 2007) | 1 line Add Collin Winter for access to update PEP 3107 ........ r53262 | andrew.kuchling | 2007-01-05 15:22:17 +0100 (Fri, 05 Jan 2007) | 1 line [Bug #1622533] Make docstrings raw strings because they contain control characters (\0, \1) ........ r53264 | andrew.kuchling | 2007-01-05 16:51:24 +0100 (Fri, 05 Jan 2007) | 1 line [Patch #1520904] Fix bsddb tests to write to the temp directory instead of the Lib/bsddb/test directory ........ r53279 | brett.cannon | 2007-01-05 22:45:09 +0100 (Fri, 05 Jan 2007) | 3 lines Silence a warning from gcc 4.0.1 by specifying a function's parameter list is 'void' instead of just a set of empty parentheses. ........ r53285 | raymond.hettinger | 2007-01-06 02:14:41 +0100 (Sat, 06 Jan 2007) | 2 lines SF# 1409443: Expand comment to cover the interaction between f->f_lasti and the PREDICT macros. ........ r53286 | anthony.baxter | 2007-01-06 05:45:54 +0100 (Sat, 06 Jan 2007) | 1 line update to (c) years to include 2007 ........ r53291 | neal.norwitz | 2007-01-06 22:24:35 +0100 (Sat, 06 Jan 2007) | 1 line Add Josiah to SF for maintaining asyncore/asynchat ........ r53293 | peter.astrand | 2007-01-07 09:53:46 +0100 (Sun, 07 Jan 2007) | 1 line Re-implemented fix for #1531862 once again, in a way that works with Python 2.2. Fixes bug #1603424. ........ r53295 | peter.astrand | 2007-01-07 15:34:16 +0100 (Sun, 07 Jan 2007) | 1 line Avoid O(N**2) bottleneck in _communicate_(). Fixes #1598181. ........ r53300 | raymond.hettinger | 2007-01-08 19:09:20 +0100 (Mon, 08 Jan 2007) | 1 line Fix zero-length corner case for iterating over a mutating deque. ........ r53301 | vinay.sajip | 2007-01-08 19:50:32 +0100 (Mon, 08 Jan 2007) | 4 lines Bare except clause removed from SMTPHandler.emit(). Now, only ImportError is trapped. Bare except clause removed from SocketHandler.createSocket(). Now, only socket.error is trapped. (SF #411881) ........ r53302 | vinay.sajip | 2007-01-08 19:51:46 +0100 (Mon, 08 Jan 2007) | 2 lines Bare except clause removed from LogRecord.__init__. Now, only ValueError, TypeError and AttributeError are trapped. (SF #411881) ........ r53303 | vinay.sajip | 2007-01-08 19:52:36 +0100 (Mon, 08 Jan 2007) | 1 line Added entries about removal of some bare except clauses from logging. ........
250 lines
11 KiB
Text
250 lines
11 KiB
Text
NOTES ON OPTIMIZING DICTIONARIES
|
|
================================
|
|
|
|
|
|
Principal Use Cases for Dictionaries
|
|
------------------------------------
|
|
|
|
Passing keyword arguments
|
|
Typically, one read and one write for 1 to 3 elements.
|
|
Occurs frequently in normal python code.
|
|
|
|
Class method lookup
|
|
Dictionaries vary in size with 8 to 16 elements being common.
|
|
Usually written once with many lookups.
|
|
When base classes are used, there are many failed lookups
|
|
followed by a lookup in a base class.
|
|
|
|
Instance attribute lookup and Global variables
|
|
Dictionaries vary in size. 4 to 10 elements are common.
|
|
Both reads and writes are common.
|
|
|
|
Builtins
|
|
Frequent reads. Almost never written.
|
|
Size 126 interned strings (as of Py2.3b1).
|
|
A few keys are accessed much more frequently than others.
|
|
|
|
Uniquification
|
|
Dictionaries of any size. Bulk of work is in creation.
|
|
Repeated writes to a smaller set of keys.
|
|
Single read of each key.
|
|
Some use cases have two consecutive accesses to the same key.
|
|
|
|
* Removing duplicates from a sequence.
|
|
dict.fromkeys(seqn).keys()
|
|
|
|
* Counting elements in a sequence.
|
|
for e in seqn:
|
|
d[e] = d.get(e,0) + 1
|
|
|
|
* Accumulating references in a dictionary of lists:
|
|
|
|
for pagenumber, page in enumerate(pages):
|
|
for word in page:
|
|
d.setdefault(word, []).append(pagenumber)
|
|
|
|
Note, the second example is a use case characterized by a get and set
|
|
to the same key. There are similar use cases with a __contains__
|
|
followed by a get, set, or del to the same key. Part of the
|
|
justification for d.setdefault is combining the two lookups into one.
|
|
|
|
Membership Testing
|
|
Dictionaries of any size. Created once and then rarely changes.
|
|
Single write to each key.
|
|
Many calls to __contains__() or has_key().
|
|
Similar access patterns occur with replacement dictionaries
|
|
such as with the % formatting operator.
|
|
|
|
Dynamic Mappings
|
|
Characterized by deletions interspersed with adds and replacements.
|
|
Performance benefits greatly from the re-use of dummy entries.
|
|
|
|
|
|
Data Layout (assuming a 32-bit box with 64 bytes per cache line)
|
|
----------------------------------------------------------------
|
|
|
|
Smalldicts (8 entries) are attached to the dictobject structure
|
|
and the whole group nearly fills two consecutive cache lines.
|
|
|
|
Larger dicts use the first half of the dictobject structure (one cache
|
|
line) and a separate, continuous block of entries (at 12 bytes each
|
|
for a total of 5.333 entries per cache line).
|
|
|
|
|
|
Tunable Dictionary Parameters
|
|
-----------------------------
|
|
|
|
* PyDict_MINSIZE. Currently set to 8.
|
|
Must be a power of two. New dicts have to zero-out every cell.
|
|
Each additional 8 consumes 1.5 cache lines. Increasing improves
|
|
the sparseness of small dictionaries but costs time to read in
|
|
the additional cache lines if they are not already in cache.
|
|
That case is common when keyword arguments are passed.
|
|
|
|
* Maximum dictionary load in PyDict_SetItem. Currently set to 2/3.
|
|
Increasing this ratio makes dictionaries more dense resulting
|
|
in more collisions. Decreasing it improves sparseness at the
|
|
expense of spreading entries over more cache lines and at the
|
|
cost of total memory consumed.
|
|
|
|
The load test occurs in highly time sensitive code. Efforts
|
|
to make the test more complex (for example, varying the load
|
|
for different sizes) have degraded performance.
|
|
|
|
* Growth rate upon hitting maximum load. Currently set to *2.
|
|
Raising this to *4 results in half the number of resizes,
|
|
less effort to resize, better sparseness for some (but not
|
|
all dict sizes), and potentially doubles memory consumption
|
|
depending on the size of the dictionary. Setting to *4
|
|
eliminates every other resize step.
|
|
|
|
Tune-ups should be measured across a broad range of applications and
|
|
use cases. A change to any parameter will help in some situations and
|
|
hurt in others. The key is to find settings that help the most common
|
|
cases and do the least damage to the less common cases. Results will
|
|
vary dramatically depending on the exact number of keys, whether the
|
|
keys are all strings, whether reads or writes dominate, the exact
|
|
hash values of the keys (some sets of values have fewer collisions than
|
|
others). Any one test or benchmark is likely to prove misleading.
|
|
|
|
While making a dictionary more sparse reduces collisions, it impairs
|
|
iteration and key listing. Those methods loop over every potential
|
|
entry. Doubling the size of dictionary results in twice as many
|
|
non-overlapping memory accesses for keys(), items(), values(),
|
|
__iter__(), iterkeys(), iteritems(), itervalues(), and update().
|
|
Also, every dictionary iterates at least twice, once for the memset()
|
|
when it is created and once by dealloc().
|
|
|
|
|
|
Results of Cache Locality Experiments
|
|
-------------------------------------
|
|
|
|
When an entry is retrieved from memory, 4.333 adjacent entries are also
|
|
retrieved into a cache line. Since accessing items in cache is *much*
|
|
cheaper than a cache miss, an enticing idea is to probe the adjacent
|
|
entries as a first step in collision resolution. Unfortunately, the
|
|
introduction of any regularity into collision searches results in more
|
|
collisions than the current random chaining approach.
|
|
|
|
Exploiting cache locality at the expense of additional collisions fails
|
|
to payoff when the entries are already loaded in cache (the expense
|
|
is paid with no compensating benefit). This occurs in small dictionaries
|
|
where the whole dictionary fits into a pair of cache lines. It also
|
|
occurs frequently in large dictionaries which have a common access pattern
|
|
where some keys are accessed much more frequently than others. The
|
|
more popular entries *and* their collision chains tend to remain in cache.
|
|
|
|
To exploit cache locality, change the collision resolution section
|
|
in lookdict() and lookdict_string(). Set i^=1 at the top of the
|
|
loop and move the i = (i << 2) + i + perturb + 1 to an unrolled
|
|
version of the loop.
|
|
|
|
This optimization strategy can be leveraged in several ways:
|
|
|
|
* If the dictionary is kept sparse (through the tunable parameters),
|
|
then the occurrence of additional collisions is lessened.
|
|
|
|
* If lookdict() and lookdict_string() are specialized for small dicts
|
|
and for largedicts, then the versions for large_dicts can be given
|
|
an alternate search strategy without increasing collisions in small dicts
|
|
which already have the maximum benefit of cache locality.
|
|
|
|
* If the use case for a dictionary is known to have a random key
|
|
access pattern (as opposed to a more common pattern with a Zipf's law
|
|
distribution), then there will be more benefit for large dictionaries
|
|
because any given key is no more likely than another to already be
|
|
in cache.
|
|
|
|
* In use cases with paired accesses to the same key, the second access
|
|
is always in cache and gets no benefit from efforts to further improve
|
|
cache locality.
|
|
|
|
Optimizing the Search of Small Dictionaries
|
|
-------------------------------------------
|
|
|
|
If lookdict() and lookdict_string() are specialized for smaller dictionaries,
|
|
then a custom search approach can be implemented that exploits the small
|
|
search space and cache locality.
|
|
|
|
* The simplest example is a linear search of contiguous entries. This is
|
|
simple to implement, guaranteed to terminate rapidly, never searches
|
|
the same entry twice, and precludes the need to check for dummy entries.
|
|
|
|
* A more advanced example is a self-organizing search so that the most
|
|
frequently accessed entries get probed first. The organization
|
|
adapts if the access pattern changes over time. Treaps are ideally
|
|
suited for self-organization with the most common entries at the
|
|
top of the heap and a rapid binary search pattern. Most probes and
|
|
results are all located at the top of the tree allowing them all to
|
|
be located in one or two cache lines.
|
|
|
|
* Also, small dictionaries may be made more dense, perhaps filling all
|
|
eight cells to take the maximum advantage of two cache lines.
|
|
|
|
|
|
Strategy Pattern
|
|
----------------
|
|
|
|
Consider allowing the user to set the tunable parameters or to select a
|
|
particular search method. Since some dictionary use cases have known
|
|
sizes and access patterns, the user may be able to provide useful hints.
|
|
|
|
1) For example, if membership testing or lookups dominate runtime and memory
|
|
is not at a premium, the user may benefit from setting the maximum load
|
|
ratio at 5% or 10% instead of the usual 66.7%. This will sharply
|
|
curtail the number of collisions but will increase iteration time.
|
|
The builtin namespace is a prime example of a dictionary that can
|
|
benefit from being highly sparse.
|
|
|
|
2) Dictionary creation time can be shortened in cases where the ultimate
|
|
size of the dictionary is known in advance. The dictionary can be
|
|
pre-sized so that no resize operations are required during creation.
|
|
Not only does this save resizes, but the key insertion will go
|
|
more quickly because the first half of the keys will be inserted into
|
|
a more sparse environment than before. The preconditions for this
|
|
strategy arise whenever a dictionary is created from a key or item
|
|
sequence and the number of *unique* keys is known.
|
|
|
|
3) If the key space is large and the access pattern is known to be random,
|
|
then search strategies exploiting cache locality can be fruitful.
|
|
The preconditions for this strategy arise in simulations and
|
|
numerical analysis.
|
|
|
|
4) If the keys are fixed and the access pattern strongly favors some of
|
|
the keys, then the entries can be stored contiguously and accessed
|
|
with a linear search or treap. This exploits knowledge of the data,
|
|
cache locality, and a simplified search routine. It also eliminates
|
|
the need to test for dummy entries on each probe. The preconditions
|
|
for this strategy arise in symbol tables and in the builtin dictionary.
|
|
|
|
|
|
Readonly Dictionaries
|
|
---------------------
|
|
Some dictionary use cases pass through a build stage and then move to a
|
|
more heavily exercised lookup stage with no further changes to the
|
|
dictionary.
|
|
|
|
An idea that emerged on python-dev is to be able to convert a dictionary
|
|
to a read-only state. This can help prevent programming errors and also
|
|
provide knowledge that can be exploited for lookup optimization.
|
|
|
|
The dictionary can be immediately rebuilt (eliminating dummy entries),
|
|
resized (to an appropriate level of sparseness), and the keys can be
|
|
jostled (to minimize collisions). The lookdict() routine can then
|
|
eliminate the test for dummy entries (saving about 1/4 of the time
|
|
spent in the collision resolution loop).
|
|
|
|
An additional possibility is to insert links into the empty spaces
|
|
so that dictionary iteration can proceed in len(d) steps instead of
|
|
(mp->mask + 1) steps. Alternatively, a separate tuple of keys can be
|
|
kept just for iteration.
|
|
|
|
|
|
Caching Lookups
|
|
---------------
|
|
The idea is to exploit key access patterns by anticipating future lookups
|
|
based on previous lookups.
|
|
|
|
The simplest incarnation is to save the most recently accessed entry.
|
|
This gives optimal performance for use cases where every get is followed
|
|
by a set or del to the same key.
|