使用模板标记的线程安全性

9

阅读完关于线程安全的这份文档后,我感觉文档中似乎有些东西缺失了,或者是我的理解或推理出现了问题。

我们来举一个简单的例子:

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()

我理解这段代码是在hello_world标签被使用时构造一个HelloWorldNode类的新实例。其他例子包括向构造函数传递参数,例如:

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)

因此,当执行hello_world时,将创建一个新的HelloWorldNode实例,并且该实例字典具有一个属性message。这个实例必须仅用于呈现给定标记实例,因为将其用于其他呈现将意味着绑定到它的数据将不正确。如果这不是这种情况,那么参数将在不同用途的标记之间混淆。
从文档中查看其他示例,以下是来自此处的简化示例:
def do_current_time(parser, token):
    tag_name, format_string = token.split_contents()
    return CurrentTimeNode(format_string[1:-1])

由于当前时间节点(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()

文档指出,如果两个页面使用相同的标签并且同时使用同一个节点,则可能会出现竞争条件。但是,如果它们都独立实例化自己的节点,我不明白两个模板的渲染如何最终共享同一实例。

文档中提到解决此问题的方法如下:

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()

这似乎是使用self来索引context.render_context。这意味着self被用来以以下两种方式之一标识实例:

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

如果1成立,为什么不只是将数据与self关联?

如果2成立,且渲染上下文“与当前正在渲染的模板的上下文相关联”,如何区分同一页上两个模板标记的两个实例?

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

1个回答

1

通过仔细阅读this,我明白了。

模板在加载时被编译。传递给标签函数的任何参数都是“静态”的。它们可以是字面字符串,也可以是用作标识符以查找渲染上下文中绑定变量的字符串。

因此,每个标签都会实例化一个Node对象,并准备好在模板使用时使用(自然地,模板可以在任意数量的线程中使用)。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接