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 шт):

Автор решения: Pavel Durmanov

В целом да, нельзя создавать 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

Подробнее про реализацию можно почитать тут.

→ Ссылка