TGTGInsighttelegram intelligenceLIVE / telegram public index
← Python Заметки

TGINSIGHT SIMILAR POSTS

Најди сличен содржај

Изворен канал @pythonotes · Post #429 · пред 17 дена

Мы рассмотрели два способа управления конеткстом переменных. Если вам показалось, что это выглядит излишне и можно было бы оставить один, то вам не показалось. Способ с threading.local придуман для разделения переменных между потоками. CоntextVar был добавлен как новый метод для асинхронного кода, но оказался настолько универсальным, что его можно использовать и с потоками. После появления ContextVar в PEP567 его рекомендовано использовать вместо threading.local. И даже был сделан бекпорт для версия ниже 3.7.1. Теперь, если совместить ContextVar и Proxy-класс из прошлого примера то получим такой класс↗️. Но у этого класса есть две проблемы: 1️⃣ Нигде не вызывается reset для сброса переменной, что может приводить проблемам - утечка памяти - "грязный" конеткст при переиспользовании потоков - невозможность вернуться к дефолту Решим это с помощью конектстного менеджера: @contextlib.contextmanager def configure_context(self, *args, **kwargs): """Синхронный контекстный менеджер (для `with`)""" tok_cfg = self._cv_config.set((args, kwargs)) tok_obj = self._cv_object.set(None) try: yield self finally: self._cv_object.reset(tok_obj) self._cv_config.reset(tok_cfg) @contextlib.asynccontextmanager async def aconfigure_context(self, *args, **kwargs): """Асинхронный контекстный менеджер (для `async with`)""" tok_cfg = self._cv_config.set((args, kwargs)) tok_obj = self._cv_object.set(None) try: yield self finally: self._cv_object.reset(tok_obj) self._cv_config.reset(tok_cfg) Пример использования: with proxy.configure_context(val1, val2): proxy.do_something() Теперь прокси готов, но... 2️⃣ В асинхронном коде, для которого и придуманы ContextVar, созданием корутин занимается Event Loop, именно он отвечает за наследование контекста дочерними корутинами. В случае с потоками ничего такого нет, мы сами себе "эвентлуп", поэтому приходится прописывать копирование конеткста самстоятельно. Пример проблемы с отсутствием наследованием конеткста в потоках↗️ Для решения есть функция копирования текущего контекста и метод запуска функции с новым конектстом: сontextvars.copy_context().run(func, *args, **kwargs) Здесь сложно придумать универсальное автоматическое копирование контекста, самая простая функция будет выглядеть так: def run_in_thread_with_context( func: Callable, *args, **kwargs ) -> threading.Thread: ctx = contextvars.copy_context() t = threading.Thread( target=lambda: ctx.run(func, *args, **kwargs) ) t.start() return t И если вернуться к нашему синхронному ApiClient, то придётся следить за конектстом самостоятельно. И если где-то в коде библиотеки уже есть вызов тредов, то это работать не будет, придется переписывать. threading.local тоже не наследует конеткст. Полный пример Proxy с CоntextVar↗️ Пример использования: client = ContextVarProxy(ApiClient) def worker_in_thread(token): with client.configure_context(token=token): use_client(...) Еще вариант, это кастомные ThreadExecutor и Thread с поддержкой автокопирования контекста. Забираем здесь↗️ И нет, это не пример как надо делать в проде) Это просто эксперемент для понимания процесса. #tricks

Hashtags

Резултати

Пронајдени 1 слични објави

Глобално пребарување

sudo recast

@sudo_recast · Post #918 · 17.04.2025 г., 09:47

A useful command when you encounter conflicts while cherry-picking: tig HEAD $(git rev-parse CHERRY_PICK_HEAD 2>/dev/null) -- $(git diff --name-only --diff-filter=U | head -1) #tricks@sudo_recast

Hashtags