【问题标题】:Thread Safety with Template Tags带有模板标签的线程安全
【发布时间】:2011-11-20 23:03:27
【问题描述】:

在阅读了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()

每当使用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 属性。这个实例肯定只能用于渲染标签的给定实例,因为将它用于其他渲染意味着绑定到它的数据将是不正确的。如果不是这种情况,参数会在标签的不同用途之间混淆。

查看文档中的其他示例,这是来自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()

这似乎用self 索引context.render_context。这意味着self 用于通过以下两种方式之一来识别实例:

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

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

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

是否在每次调用标签时单独实例化节点?如果是这样,为什么会出现并发问题?如果不是,为什么不呢?

【问题讨论】:

    标签: python django concurrency django-templates


    【解决方案1】:

    仔细阅读this就知道了。

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

    因此,Node 对象会针对每个标签进行实例化,并且在使用模板时随时待命(当然,模板可以在任意数量的线程中使用)。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-26
      • 1970-01-01
      • 2012-12-02
      • 1970-01-01
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      相关资源
      最近更新 更多