contextvars утечка памяти
Разбираюсь с пакетом contextvars. Увидел комментарий в документации:
Important: Context Variables should be created at the top module level and never in closures. Context objects hold strong references to context variables which prevents context variables from being properly garbage collected.
Что понимается под использованием в верху модуля? Нельзя использовать внутрии функции? Означает ли это, что я могу поймать утчеку памяти? Что это означает?
Ответы (1 шт):
В целом да, нельзя создавать contextvars внутри функций, разве что в мейне.
Суть в том что текущий тред ссылается на Context object, а Context держит ссылки на contextvars. Соответственно пока жив тред - жив и контекст со всеми его contextvars.
На этом примере видно, что contextvars не удаляются, хотя мы вышли их контекста фцнкции:
In [2]: import contextvars
In [3]: def foo():
...: var = contextvars.ContextVar("var")
...: var.set(0)
...: print(var, var.get())
...:
In [4]: foo()
<ContextVar name='var' at 0x10e222fc0> 0
In [5]: foo()
<ContextVar name='var' at 0x10e1fb308> 0
In [6]: foo()
<ContextVar name='var' at 0x10e1fb6d0> 0
In [7]: list(contextvars.copy_context().items())
Out[7]:
[(<ContextVar name='var' at 0x10e1fb308>, 0),
(<ContextVar name='var' at 0x10e222fc0>, 0),
(<ContextVar name='var' at 0x10e1fb6d0>, 0)]
Но если запустить функцию в треде (т.е в другом контексте), то по завершению этого треда, контекст будет очищен:
In [9]: from threading import Thread
In [10]: len(contextvars.copy_context())
Out[10]: 3
In [11]: Thread(target=foo).start()
<ContextVar name='var' at 0x10e24ef68> 0
In [12]: len(contextvars.copy_context())
Out[12]: 3
Подробнее про реализацию можно почитать тут.