线程安全与模板标签

Joe*_*Joe 9 python django concurrency django-templates

在阅读了有关线程安全的文档之后,我感到文档中缺少某些内容,或者我的阅读或我的推理.

我们举一个简单的例子:

class HelloWorldNode(template.Node):
    def render(self, context):
        return "O HAI LOL"

@register.tag(name="hello_world")
def hello_world(parser, tokens):
    """
    Greets the world with wide-eyed awe.
    """
    return HelloWorldNode()
Run Code Online (Sandbox Code Playgroud)

我理解这个代码,HelloWorldNode只要使用hello_world标记,就构造一个新的类实例.其他示例涉及将参数传递给构造函数,如下所示:

class HelloWorldNode(template.Node):
    def __init__(self, message):
        self.message = message

    def render(self, context):
        return "O HAI LOL " + message

@register.tag(name="hello_world")
def hello_world(parser, tokens):
    """
    Greets the world with wide-eyed awe.
    """

    message = tokens.split_contents()[1]

    return HelloWorldNode(message)
Run Code Online (Sandbox Code Playgroud)

因此,在hello_world执行时,会创建一个新的HelloWorldNode实例,并且实例字典具有一个属性message.此实例肯定必须仅用于呈现标记的给定实例,因为将其用于其他呈现将意味着绑定到它的数据将是不正确的.如果不是这种情况,那么参数会在标签的不同用途之间混淆.

看着从文档其他例子,这里是从一个简单的例子在这里:

def do_current_time(parser, token):
    tag_name, format_string = token.split_contents()
    return CurrentTimeNode(format_string[1:-1])
Run Code Online (Sandbox Code Playgroud)

因为这会从传递给函数的标记中获取数据,所以CurrentTimeNode可以工作的唯一方法是每次do_current_time调用一个新的实例化.

回到文档页面,不和之处.这是'坏'.

class CycleNode(Node):
    def __init__(self, cyclevars):
        self.cycle_iter = itertools.cycle(cyclevars)
    def render(self, context):
        return self.cycle_iter.next()
Run Code Online (Sandbox Code Playgroud)

该文档说,如果两个页面都使用相同的节点,那么使用相同标签的两个页面可能会遇到竞争条件.我不明白如果两个模板的渲染都独立地实例化它们,它们最终会如何共享同一个实例.

解决这个问题的方法,说文档是这样的:

class CycleNode(Node):
    def __init__(self, cyclevars):
        self.cyclevars = cyclevars
    def render(self, context):
        if self not in context.render_context:
            context.render_context[self] = itertools.cycle(self.cyclevars)
        cycle_iter = context.render_context[self]
        return cycle_iter.next()
Run Code Online (Sandbox Code Playgroud)

这似乎指数context.render_contextself.其含义必须self用于以两种方式之一识别实例:

  1. self 引用整个系统中该类的一个特定实例
  2. self 仅引用该类,并且为了引用该实例,需要渲染上下文

如果1为真,为什么不将数据与self?关联?

如果2为真,并且渲染上下文"与当前正在渲染的模板的上下文相关联",如何在同一页面上区分模板标记的两个实例?

每次调用标记时,Node都会单独实例化吗?如果是这样,为什么并发问题呢?如果没有,为什么不呢?

Joe*_*Joe 1

仔细阅读后明白了。

模板在加载时进行编译。传递到标记函数的任何参数都是“静态”的。它们要么是文字字符串,要么是用作标识符以在渲染上下文中查找绑定变量的字符串。

因此,Node 对象会为每个标签实例化,并且每当使用模板时都会挂起以供使用(当然,模板可以在任意数量的线程中使用)。

因此,self我的问题是模板中特定节点的身份。与渲染上下文相结合,这提供了用于挂起实例变量的唯一标识。