【发布时间】: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 用于通过以下两种方式之一来识别实例:
-
self在整个系统中引用了该类的一个特定实例 -
self仅引用该类,并且为了引用该实例,需要渲染上下文
如果 1 为真,为什么不将数据与 self 关联?
如果 2 为真,并且渲染上下文是“与当前正在渲染的模板的上下文相关联”,那么如何区分同一页面上的模板标签的两个实例?
是否在每次调用标签时单独实例化节点?如果是这样,为什么会出现并发问题?如果不是,为什么不呢?
【问题讨论】:
标签: python django concurrency django-templates