Python 3.7 fügte das Kontextvars-Modul (https://docs.python.org/ja/3/library/contextvars.html) hinzu und führte die ContextVar-Klasse für Asyncio ein.
Wie Thread Local (in Python threading.local ()), das eindeutige Daten für jeden Thread enthalten kann Darüber hinaus besteht die Funktion von ContextVar darin, dass jedes Collout eindeutige Daten enthalten kann.
Als ich ContextVar tatsächlich verwendete, stieß ich auf das Phänomen, dass der Datensatz in ContextVar verschwand. Daher schrieb ich erneut einen Bestätigungscode und untersuchte das Verhalten.
Im folgenden Code führen wir zwei Collout-Funktionen aus, "parent_await_coroutine ()" und "parent_create_new_task ()", und setzen in jeder Funktion den Wert auf ContextVar und rufen die Funktion "child ()" auf.
Diese child ()
Funktion ändert den von ContextVar abgerufenen Wert.
Die beiden übergeordneten Funktionen rufen die untergeordnete Funktion unterschiedlich auf. Ersteres wartet auf die Coroutine und letzteres erstellt und führt eine neue Aufgabe aus, die die Coroutine umschließt.
Bei der Ausführung als letztere neue Aufgabe werden einige der Änderungen, die an der ContextVar in der untergeordneten Funktion vorgenommen wurden, nicht in der übergeordneten Funktion wiedergegeben. Insbesondere fügt die untergeordnete Funktion den Wert von number_var
ContextVar hinzu und setzt ihn zurück, aber die übergeordnete Funktion liest die Änderung nicht (wie vor dem Aufruf der untergeordneten Funktion).
Andererseits sind Änderungen an den ContextVar-Objekten msg_var
to Msg auch für die übergeordnete Funktion sichtbar.
Dies liegt daran, dass der Inhalt von Kontextvars beim Erstellen der neuen Aufgabe kopiert wurde. Sie können dies aus PEP 567 lesen. Wenn bei diesem Kopiervorgang int von "number_var" int ist, wird der Wert kopiert und auf das Msg-Objekt von "msg_var" wird kopiert (d. H. Flache Kopie), sodass davon ausgegangen wird, dass das obige Verhalten ausgeführt wird. ..
import asyncio
import contextvars
class Msg:
"""Nur eine Textcontainerklasse.
Wird verwendet, um die flache Kopie von Kontextvars zu überprüfen.
"""
def __init__(self, text: str):
self._text = text
@property
def text(self) -> str:
return self._text
@text.setter
def text(self, val):
self._text = val
msg_var: contextvars.ContextVar[Msg] = contextvars.ContextVar('msg_var')
number_var: contextvars.ContextVar[int] = contextvars.ContextVar('number_var')
async def child():
#Holen Sie sich die Nummer von ContextVar und fügen Sie 1 hinzu
n = number_var.get()
print(f'child: number={n}') # child: number=1
n += 1
number_var.set(n)
#Holen Sie sich das Msg-Objekt aus ContextVar und ändern Sie den Text
msg = msg_var.get()
print(f'child: msg="{msg.text}"') # child: msg="msg created by parent"
msg.text = 'msg changed by child'
#Dieses Kind()Verarbeitung zur Ausführung der asynchronen Funktion
await asyncio.sleep(0.1)
async def parent_await_coroutine():
n = 1
number_var.set(n)
m = Msg('msg created by parent')
msg_var.set(m)
print(f'parent: number={n}') # parent: number=1
print(f'parent: msg="{m.text}"') # parent: msg="msg created by parent"
await child()
n = number_var.get()
m = msg_var.get()
print(f'parent: number={n}') # parent: number=2
print(f'parent: msg="{m.text}"') # parent: msg="msg changed by child"
async def parent_create_new_task():
n = 1
number_var.set(n)
m = Msg('msg created by parent')
msg_var.set(m)
print(f'parent: number={n}') # parent: number=1
print(f'parent: msg="{m.text}"') # parent: msg="msg created by parent"
await asyncio.create_task(child())
n = number_var.get()
m = msg_var.get()
print(f'parent: number={n}') # parent: number=1
print(f'parent: msg="{m.text}"') # parent: msg="msg changed by child"
if __name__ == '__main__':
asyncio.run(parent_create_new_task())
asyncio.run(parent_await_coroutine())
Recommended Posts