线程安全与模板标签

时间:2011-09-20 10:11:03

标签: python django concurrency django-templates

在阅读this document关于线程安全的内容后,我感到文档中缺少某些内容,或者我的阅读内容或我的推理。

我们举一个简单的例子:

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

我理解这段代码,只要使用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)

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

查看文档中的其他示例,这是here的简化示例:

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

这似乎用context.render_context索引self。其含义必须是self用于以两种方式之一识别实例:

  1. self引用整个系统中该类的一个特定实例
  2. self仅引用该类,并且为了引用该实例,需要渲染上下文
  3. 如果1为真,为什么不将数据与self相关联?

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

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

1 个答案:

答案 0 :(得分:0)

仔细阅读this

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

因此Node对象被实例化为每个标记,并且只要使用模板就可以随时使用(当然,模板可以在任意数量的线程中使用)。

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