ContextVars через модули - PullRequest
1 голос
/ 30 мая 2019

Я совершенно новичок в asyncio и ContextVars, я только что прочитал, что нового в 3.7 и обнаружил ContextVars, я изо всех сил пытаюсь понять, как он используется, все, что я знаю, это полезно в сопрограммах, вместо использования thread.local следуетиспользуйте ContextVars.Но ни один из официальных результатов поиска в doc и top google не может помочь мне по-настоящему понять его назначение.

Итак, являются ли выпуклые столбцы общими для всех модулей?Я попытался:

example.py

from contextvars import ContextVar

number = ContextVar('number', default=100)
number.set(1)

, затем я пытаюсь импортировать number.py

(playground) Jamess-MacBook-Pro-2:playground jlin$ python3.7
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 26 2018, 23:26:24) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import example
>>> from contextvars import ContextVar
>>> number = ContextVar('number', default=200)
>>> number.get()
200

Я ожидал, что number.get() вернет 1, но, очевидно,Я неправильно понял его цель.

Может кто-нибудь помочь мне понять это?

Ответы [ 4 ]

1 голос
/ 31 мая 2019

Предположим, вы используете Python thread.local для хранения вашей глобальной переменной потока в многопоточном приложении.

Например, вы храните django request глобально в thread.local

  • весь ваш код имеет доступ к текущему (и правильному) request экземпляру
  • itработает, , потому что каждый HTTP-запрос django обрабатывается в своем собственном потоке Python

Не думайте, что вы обрабатываете HTTP-запросы в asyncio как неблокирующий код, выполняемый в том же потоке Python.

  • HTTP-запрос, хранящийся в thread.local, не будет работать, поскольку несколько одновременных запросов обрабатываются в одном потоке Python
  • Что происходит, если вы перезаписываете одно и то же thread.local переменная и весь ваш код имеет доступ к самой последней (неправильной) request экземпляр

В этом случае вы используете ContextVars, предназначенную для использования в этом случае внутри одновременной неблокируемойзадания, выполняющиеся в том же потоке Python.

0 голосов
/ 30 мая 2019

Вы переназначаете значение number.Прямой вызов переменной из модуля, например example.number.get().


Простое приложение заменяет глобальную переменную.

Дано

import random
import contextvars as cv

Код

Здесь мы будем подражать случайному блужданию.Как и глобальная переменная, мы можем делить состояние между функциями:

move = cv.ContextVar("move", default="")


def go_left():
    value = move.get()
    move.set(value + "L")


def go_right():
    value = move.get()
    move.set(value + "R")


def random_walk(steps):
    directions = [go_left, go_right]
    while steps:
        random.choice(directions)()
        steps -= 1
    return move.get()

Демо

ContextVar действует как глобальная переменная, которая обновляется случайным образомсобытия:

random_walk(1)
# 'R'
random_walk(2)
# 'RLL'
random_walk(3)
# 'RLLLRL'

Помимо обычной глобальной переменной, ContextVar:

0 голосов
/ 31 мая 2019

Не совсем уверен, что мой подход правильный, но я добавлю свои выводы, чтобы ответить, поэтому я попытался использовать это в моем проекте django, чтобы установить request var без использования локального потока.

from contextvars import ContextVar
request_var = ContextVar('request', default=None)


def request_middleware(get_response):
    """
    Sets the request into contextvar
    """
    def middleware(request):
        ctx = copy_context()
        return ctx.run(wrap_get_response, request)

    def wrap_get_response(request):
        request_var.set(request)
        return get_response(request)
    return middleware

Затем в другом месте, где нужно использовать request var:

from core.middlewares import request_var
request = request_var.get()

Не уверен, что это правильное использование, но мне кажется, что оно работает нормально.

Я нене знаю, как получить request_var из context.get (), например.

from contextvars import copy_context
ctx = copy_context()
# the key here is `request_var` obj in middlewares.py, 
# might as well just import `request_var` and use it directly?
request = ctx.get(...)  
0 голосов
/ 30 мая 2019

Вы снова присвоили значение номеру.Вот почему он показывает 200 из последнего обновления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...