comparison env/lib/python3.9/site-packages/boltons/gcutils.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # -*- coding: utf-8 -*-
2 """The Python Garbage Collector (`GC`_) doesn't usually get too much
3 attention, probably because:
4
5 - Python's `reference counting`_ effectively handles the vast majority of
6 unused objects
7 - People are slowly learning to avoid implementing `object.__del__()`_
8 - The collection itself strikes a good balance between simplicity and
9 power (`tunable generation sizes`_)
10 - The collector itself is fast and rarely the cause of long pauses
11 associated with GC in other runtimes
12
13 Even so, for many applications, the time will come when the developer
14 will need to track down:
15
16 - Circular references
17 - Misbehaving objects (locks, ``__del__()``)
18 - Memory leaks
19 - Or just ways to shave off a couple percent of execution time
20
21 Thanks to the :mod:`gc` module, the GC is a well-instrumented entry
22 point for exactly these tasks, and ``gcutils`` aims to facilitate it
23 further.
24
25 .. _GC: https://docs.python.org/2/glossary.html#term-garbage-collection
26 .. _reference counting: https://docs.python.org/2/glossary.html#term-reference-count
27 .. _object.__del__(): https://docs.python.org/2/glossary.html#term-reference-count
28 .. _tunable generation sizes: https://docs.python.org/2/library/gc.html#gc.set_threshold
29 """
30 # TODO: type survey
31
32 from __future__ import print_function
33
34 import gc
35 import sys
36
37 __all__ = ['get_all', 'GCToggler', 'toggle_gc', 'toggle_gc_postcollect']
38
39
40 def get_all(type_obj, include_subtypes=True):
41 """Get a list containing all instances of a given type. This will
42 work for the vast majority of types out there.
43
44 >>> class Ratking(object): pass
45 >>> wiki, hak, sport = Ratking(), Ratking(), Ratking()
46 >>> len(get_all(Ratking))
47 3
48
49 However, there are some exceptions. For example, ``get_all(bool)``
50 returns an empty list because ``True`` and ``False`` are
51 themselves built-in and not tracked.
52
53 >>> get_all(bool)
54 []
55
56 Still, it's not hard to see how this functionality can be used to
57 find all instances of a leaking type and track them down further
58 using :func:`gc.get_referrers` and :func:`gc.get_referents`.
59
60 ``get_all()`` is optimized such that getting instances of
61 user-created types is quite fast. Setting *include_subtypes* to
62 ``False`` will further increase performance in cases where
63 instances of subtypes aren't required.
64
65 .. note::
66
67 There are no guarantees about the state of objects returned by
68 ``get_all()``, especially in concurrent environments. For
69 instance, it is possible for an object to be in the middle of
70 executing its ``__init__()`` and be only partially constructed.
71 """
72 # TODO: old-style classes
73 if not isinstance(type_obj, type):
74 raise TypeError('expected a type, not %r' % type_obj)
75 try:
76 type_is_tracked = gc.is_tracked(type_obj)
77 except AttributeError:
78 type_is_tracked = False # Python 2.6 and below don't get the speedup
79 if type_is_tracked:
80 to_check = gc.get_referrers(type_obj)
81 else:
82 to_check = gc.get_objects()
83
84 if include_subtypes:
85 ret = [x for x in to_check if isinstance(x, type_obj)]
86 else:
87 ret = [x for x in to_check if type(x) is type_obj]
88 return ret
89
90
91 _IS_PYPY = '__pypy__' in sys.builtin_module_names
92 if _IS_PYPY:
93 # pypy's gc is just different, y'all
94 del get_all
95
96
97 class GCToggler(object):
98 """The ``GCToggler`` is a context-manager that allows one to safely
99 take more control of your garbage collection schedule. Anecdotal
100 experience says certain object-creation-heavy tasks see speedups
101 of around 10% by simply doing one explicit collection at the very
102 end, especially if most of the objects will stay resident.
103
104 Two GCTogglers are already present in the ``gcutils`` module:
105
106 - :data:`toggle_gc` simply turns off GC at context entrance, and
107 re-enables at exit
108 - :data:`toggle_gc_postcollect` does the same, but triggers an
109 explicit collection after re-enabling.
110
111 >>> with toggle_gc:
112 ... x = [object() for i in range(1000)]
113
114 Between those two instances, the ``GCToggler`` type probably won't
115 be used much directly, but is documented for inheritance purposes.
116 """
117 def __init__(self, postcollect=False):
118 self.postcollect = postcollect
119
120 def __enter__(self):
121 gc.disable()
122
123 def __exit__(self, exc_type, exc_val, exc_tb):
124 gc.enable()
125 if self.postcollect:
126 gc.collect()
127
128
129 toggle_gc = GCToggler()
130 """A context manager for disabling GC for a code block. See
131 :class:`GCToggler` for more details."""
132
133
134 toggle_gc_postcollect = GCToggler(postcollect=True)
135 """A context manager for disabling GC for a code block, and collecting
136 before re-enabling. See :class:`GCToggler` for more details."""