Python asyncio et ContextVar

Python 3.7 a ajouté le module contextvars (https://docs.python.org/ja/3/library/contextvars.html) et a introduit la classe ContextVar pour asyncio.

Comme Thread Local (en Python, threading.local ()) qui peut avoir des données uniques pour chaque thread. De plus, la fonctionnalité de ContextVar est que chaque collout peut avoir des données uniques.

Lorsque j'ai utilisé ContextVar, j'ai rencontré un phénomène selon lequel l'ensemble de données de ContextVar avait disparu, j'ai donc réécrit un code de vérification et étudié le comportement.

Dans le code ci-dessous, nous exécutons deux fonctions collout, parent_await_coroutine () et parent_create_new_task (), et dans chaque fonction, nous définissons la valeur sur ContextVar et appelons la fonction child (). Cette fonction child () modifie la valeur extraite de ContextVar.

Les deux fonctions parents appellent la fonction enfant différemment. Le premier attend la coroutine et le second crée et exécute une nouvelle tâche qui encapsule la coroutine.

Lorsqu'elle est exécutée en tant que nouvelle nouvelle tâche, certaines des modifications apportées à la ContextVar dans la fonction enfant ne sont pas reflétées dans la fonction parent. Plus précisément, la fonction enfant ajoute la valeur de ContextVar number_var et la réinitialise, mais la fonction parent ne lit pas la modification (comme elle l'était avant d'appeler la fonction enfant). D'autre part, les modifications apportées à la ContextVar msg_var en objets Msg sont également visibles par la fonction parent.

En effet, le contenu des contextvars a été copié lors de la création de la nouvelle tâche. Vous pouvez le lire sur PEP 567. Dans ce processus de copie, si l'int de number_var est int, la valeur est copiée et l'objet Msg de msg_var est référencé copié (c'est-à-dire Copie superficielle), il est donc considéré que le comportement ci-dessus est effectué. ..

import asyncio
import contextvars


class Msg:
    """Juste une classe de conteneur de texte.
Utilisé pour vérifier la copie peu profonde des contextvars.
    """

    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():
    #Obtenez le numéro de ContextVar et ajoutez 1
    n = number_var.get()
    print(f'child: number={n}')  # child: number=1
    n += 1
    number_var.set(n)

    #Obtenez l'objet Msg de ContextVar et modifiez le texte
    msg = msg_var.get()
    print(f'child: msg="{msg.text}"')  # child: msg="msg created by parent"
    msg.text = 'msg changed by child'

    #Cet enfant()Traitement pour rendre la fonction asynchrone
    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

Python asyncio et ContextVar
[python] Compresser et décompresser
Astuces Python et Numpy
[Python] pip et roue
Itérateur et générateur Python
Paquets et modules Python
Intégration Vue-Cli et Python
Ruby, Python et carte
entrée et sortie python
Python et Ruby se séparent
Programmation avec Python et Tkinter
Chiffrement et déchiffrement avec Python
Python: variables de classe et d'instance
3-3, chaîne Python et code de caractère
Python et matériel - Utilisation de RS232C avec Python -
Python sur Ruby et Ruby en colère sur Python
Indentation Python et format de chaîne
division des nombres réels python (/) et division des nombres entiers (//)
Installez Python et Flask (Windows 10)
À propos des objets et des classes Python
À propos des variables et des objets Python
Apache mod_auth_tkt et Python AuthTkt
Å (Ongustorome) et NFC @ Python
Apprenez à connaître les packages et les modules Python
# 2 [python3] Séparation et commentaire
Copie superficielle Python et copie profonde
Mémo tranche python et rubis
Installation de Python et grammaire de base
J'ai comparé Java et Python!
Copie superficielle Python et copie profonde
À propos de Python, len () et randint ()
Installez Python 3.7 et Django 3.0 (CentOS)
Variables de classe et d'instance Python
Syntaxe Ruby et Python ~ branch ~
[Python] Python et sécurité-① Qu'est-ce que Python?
Pile et file d'attente en Python
métaclasse python et déclaration sqlalchemy
Implémentation de Fibonacci et des nombres premiers (python)
bases de python: conditions et itérations
Opérateur de bits Python et somme logique
Module de débogage et de test Python
Liste Python et tapples et virgules
Variables Python et ID d'objet
Notation et générateur d'inclusion de liste Python
À propos de Python et des expressions régulières
python avec pyenv et venv
Unittest et CI en Python
[python] Obtenir le quotient et le surplus
Fonctions de tri et de comparaison Python 3
[Python] Recherche de priorité de profondeur et recherche de priorité de largeur
Identité et équivalence: is et == en Python
Installation source et installation de Python
Python ou et et opérateur trap
Défiez Python3 et Selenium Webdriver
À propos des opérations Python et OS
Fonctions d'ordre supérieur et notation d'inclusion en Python
Installation de Python (Python 3.7.7) et grammaire de base
Python # À propos de la référence et de la copie
Fonctionne avec Python et R