Dopo aver letto this document sulla sicurezza dei thread, ho la sensazione che manchi qualcosa nella documentazione, o la mia lettura o il mio ragionamento.Sicurezza dei thread con i tag dei modelli
Diamo un semplice esempio:
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()
Compresi questo codice per creare una nuova istanza della classe HelloWorldNode
ogni volta che viene utilizzato il tag hello_world
. Altri esempi riguardanti il passaggio di argomenti al costruttore, in questo modo:
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)
Così, quando viene eseguita hello_world
, viene creata una nuova istanza di HelloWorldNode, e il dizionario dell'istanza ha un attributo message
. Questa istanza sicuramente deve essere utilizzata solo per il rendering della sola istanza del tag, in quanto il suo utilizzo per altri rendering significherebbe che i dati ad esso associati non sarebbero corretti. Se così non fosse, gli argomenti verrebbero confusi tra diversi usi del tag.
Guardando in altri esempi la documentazione, ecco un esempio semplificato da here:
def do_current_time(parser, token):
tag_name, format_string = token.split_contents()
return CurrentTimeNode(format_string[1:-1])
Dato che questo prende i dati dai gettoni passati alla funzione, l'unico modo che CurrentTimeNode può funzionare è che uno nuovo viene istanziato ogni volta che viene invocato do_current_time
.
Torna alla pagina della documentazione, in cui la dissonanza si inserisce. Questa è 'cattiva'.
class CycleNode(Node):
def __init__(self, cyclevars):
self.cycle_iter = itertools.cycle(cyclevars)
def render(self, context):
return self.cycle_iter.next()
Il dottore dice che due pagine utilizzando lo stesso tag potrebbero poi sperimentare condizioni di gara se entrambi utilizzano lo stesso nodo. Non capisco come il rendering di due modelli possa finire per condividere la stessa istanza se entrambi istanziano autonomamente il proprio.
Il modo per risolvere questo, dice la documentazione è in questo modo:
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()
Questo sembra indice context.render_context
con self
. L'implicazione di che deve essere che self
viene utilizzato per identificare l'istanza in uno dei due modi:
self
riferimenti una specifica istanza della classe in tutto il sistemaself
riferimenti quella classe solo, e al fine per fare riferimento all'istanza è necessario un contesto di rendering
Se 1 è vero, perché non associare semplicemente i dati a self
?
Se 2 è true e il contesto di rendering è "associato al contesto del modello attualmente sottoposto a rendering", come è possibile distinguere tra due istanze del tag del modello sulla stessa pagina?
Il nodo viene istanziato singolarmente ogni volta che viene richiamato il tag? Se sì, perché i problemi di concorrenza? Se no, perché no?