Mercurial > repos > shellac > sam_consensus_v3
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.""" |