[Python] À propos du multi-processus

À propos de cet article

Cet article résume ce que vous avez appris sur le multi-processus Python.

À propos du multi-processus en Python

Quand le multi-processus est-il utilisé? ⇒ Lors de la réalisation d'un traitement parallèle, il est possible de diviser le processus comme moyen de réalisation.

Les applications qui exécutent des tâches gourmandes en ressources processeur sur un processeur multicœur nécessitent actuellement l'utilisation de processus multiples pour tirer parti du processeur multicœur.

https://docs.python.org/ja/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock

Avantages du multi-processus en Python

Pour démarrer le processus

Avant de mentionner le code source utilisant le multi-processus, je mentionnerai comment démarrer un nouveau processus. Dans n'importe quel langage de programmation, la manière de démarrer un nouveau processus est de créer un fork d'un programme. En Python, en exécutant ʻos.fork () `, chaque processus s'exécute dans un espace d'adressage différent après que le contexte mémoire a copié les processus enfants. Ci-dessous, la source.

fork.py


import os

pid_list = []

def main():
    pid_list.append(os.getpid())
    child_pid = os.fork()

    if child_pid == 0:
        pid_list.append(os.getpid())
        print()
        print("Enfant: こんにちは,私はEnfantプロセスです")
        print("Enfant:Le numéro PID que je connais est%s" % pid_list)
    
    else:
        pid_list.append(os.getpid())
        print()
        print("parent:こんにちは,私はparentプロセスです")
        print("parent:Le numéro PID du processus enfant est%ré"%child_pid)
        print("parent:Le numéro PID que je connais est%s"%pid_list)

if __name__ == "__main__":
    main()

$python fork.py

parent:こんにちは,私はparentプロセスです
parent:Le numéro PID du processus enfant est 321
parent:Le numéro PID que je connais est[320, 320]est

Enfant: こんにちは,私はEnfantプロセスです
Enfant:Le numéro PID que je connais est[320, 321]est

Le processus initial a le même 320 PID, mais vous pouvez voir que le processus enfant a ajouté 321 et que les deux processus ne partagent pas un contexte de mémoire.

Mise en œuvre de la communication inter-processus

La mémoire de processus n'est pas partagée par défaut. Si vous souhaitez communiquer entre les processus, vous devez effectuer un certain travail. Pour simplifier cela, le module «multiprocessing» propose plusieurs manières de communiquer entre les processus. Les deux méthodes suivantes sont présentées ici.

À propos de multiprocessing.Pipe

La classe Pipe a un concept similaire aux pipes Unix et Linux. multiprocessing.Pipe () renvoie une paire d'objets Connection qui représentent les deux extrémités du tube. Dans l'exemple ci-dessous (pipesample.py), parent_conn, child_conn = Pipe () est applicable. La valeur par défaut «Pipe (True)» le rend bidirectionnel. Avec Pipe (False), le pipe est unidirectionnel, et avecconn1, conn2 = Pipe (), conn1 est dédié à la réception de messages et conn2 est dédié à l'envoi. La classe Pipe envoie et reçoit également des objets sélectionnables.

URL de référence: https://docs.python.org/ja/2.7/library/multiprocessing.html#pipes-and-queues

pipesample.py


from multiprocessing import Process, Pipe

class CustomClass:
    pass

def work(connection):
    while True:
        instance = connection.recv()

        if instance:
            print("Enfant:Recevoir:{}".format(instance))

        else:
            return

def main():
    parent_conn, child_conn = Pipe()

    child = Process(target=work, args=(child_conn,))

    for item in (
        42,
        'some string',
        {'one':1},
        CustomClass(),
        None,
    ):
        print("parent:Envoyer:{}".format(item))
        parent_conn.send(item)
    
    child.start()
    child.join()

if __name__ == "__main__":
    main()
$python pipesample.py
parent:Envoyer:42
parent:Envoyer:some string
parent:Envoyer:{'one': 1}
parent:Envoyer:<__main__.CustomClass object at 0x7fc785a34ac8>
parent:Envoyer:None
Enfant:Recevoir:42
Enfant:Recevoir:some string
Enfant:Recevoir:{'one': 1}
Enfant:Recevoir:<__main__.CustomClass object at 0x7fc785268978>

Si vous passez l'instance créée par for item in (42, ..., None,): à l'argument de parent.send (), le processus qui est couplé en recevant child .recv () L'état des données est transmis à. Vous pouvez également voir que les adresses de processus sont différentes.

Implémentation avec multiprocessing.sharedctypes

Dans la classe multiprocessing.sharedctypes, une mémoire partagée est créée et des types de données (type int, type double, etc.) y sont créés. Fournit un moyen d'insérer. Le type de données suit type C. Les plus basiques sont Value (typecode_or_type, * arg, lock = True) et ʻArray (typecode_or_type, size_or_initializer, *, lock = True) . typecode_or_typedétermine le type d'objet renvoyé. Il s'agit d'un type ctypes ou d'un code de type à une lettre tel qu'utilisé dans le module de tableau. Comme il est difficile de décrire la liste, le dictionnaire, l'espace de noms, le verrouillage, etc., utilisezmultiprocessing.Manager` dans ce cas. Référence: https://docs.python.org/ja/3/library/multiprocessing.html#sharing-state-between-processes

valuearray.py


from multiprocessing import Process, Value, Array

def f(n,a):
    n.value = 3.141592
    for i in range(len(a)):
        a[i] = -a[i]

if __name__ == "__main__":
    num = Value('d', 0.0)
    arr = Array('i', range(10))

    p = Process(target=f, args=(num, arr))
    p.start()
    p.join()

    print(num.value)
    print(arr[:])
$python valuearray.py
3.141592
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

Utiliser le pool de processus

L'utilisation de plusieurs processus au lieu de threads augmentera considérablement la surcharge. L'utilisation de la mémoire augmente, surtout si chaque processus a un contexte de mémoire indépendant. Par conséquent, lorsqu'un grand nombre de processus enfants est généré, l'effet néfaste est supérieur au traitement utilisant des threads. Pour les applications multi-processus, la création d'un pool de processus est un bon moyen de contrôler l'utilisation des ressources. L'idée de base d'un pool de processus est de préparer un processus spécifié à l'avance, puis de prendre des éléments de la file d'attente et de les traiter. Au lieu de démarrer le processus après l'arrivée de la tâche à traiter, démarrez le processus à l'avance afin que le processus démarre immédiatement après l'attribution de la tâche.

À propos de la classe Pool

Cette classe prend en charge tous les traitements compliqués qui gèrent plusieurs processus.

Le code source suivant utilise l'API Google Map de GCP (Google Cloud Platform) pour obtenir la latitude et la longitude correspondant au nom de la ville. En définissant POOL_SIZE = 4, quatre processus qui fonctionnent en parallèle sont spécifiés. La classe Pool peut également utiliser le gestionnaire de contexte.

geocoding_by_multiprocessing.py



from multiprocessing import Pool

from gmaps import Geocoding

api = Geocoding(api_key='secret')

PLACES = (
    'Reykjavik','Vien','Zadar',
    'Venice','Wrocow','Bolognia',
    'Berlin','Dehil','New York',
    'Osaka'
)

POOL_SIZE = 4

def fetch_place(place):
    return api.geocode(place)[0]

def present_result(geocoded):
    print("{:s}, {:6.2f}, {:6.2f}".format(
        geocoded['formatted_address'],
        geocoded['geometry']['location']['lat'],
        geocoded['geometry']['location']['lng'],
    ).encode('utf-8'))

def main():
    with Pool(POOL_SIZE) as pool:
        results = pool.map(fetch_place, PLACES)
    
    for result in results:
        present_result(result)

if __name__ == "__main__":
    main()
    
$ python geocoding_by_multiprocessing.py
b'Reykjav\xc3\xadk, Iceland,  64.15, -21.94'
b'3110 Glendale Blvd, Los Angeles, CA 90039, USA,  34.12, -118.26'
b'Zadar, Croatia,  44.12,  15.23'
b'Venice, Metropolitan City of Venice, Italy,  45.44,  12.32'
b'Wroc\xc5\x82aw, Poland,  51.11,  17.04'
b'Bologna, Metropolitan City of Bologna, Italy,  44.49,  11.34'
b'Berlin, Germany,  52.52,  13.40'
b'Delhi, India,  28.70,  77.10'
b'New York, NY, USA,  40.71, -74.01'
b'Osaka, Japan,  34.69, 135.50'

Impressions

L'étude du traitement parallèle est difficile. (Lol)

Les références

Recommended Posts

[Python] À propos du multi-processus
À propos des tranches Python
À propos du rendement Python
À propos de python, classe
À propos de Python Decorator
À propos de la référence Python
À propos des décorateurs Python
À propos de Python for loop
À propos des arguments de fonction (python)
[Python] Mémo sur les fonctions
Résumé sur Python3 + OpenCV3
À propos de Python, pour ~ (plage)
Multi-processus de manière asynchrone avec python
[Python] Mémo sur les erreurs
À propos de l'environnement de développement Python
Python: à propos des arguments de fonction
À propos de Python Pyramid Traversal
À propos de Python3 ... (objet Ellipsis)
[Python] Chapitre 01-01 À propos de Python (First Python)
[Python] À propos de l'entrée standard
À propos de __all__ en python
[Python] En savoir plus sur pip
Prise en charge de Fabric pour Python 3
Python
À propos des objets et des classes Python
À propos des variables et des objets Python
À propos du module Python venv
Multi-processus
fonction de mémorandum python pour débutant
À propos de la fonction enumerate (python)
À propos de divers encodages de Python 3
À propos de Perl, Python, PHP, Ruby
À propos de la date et du fuseau horaire Python
Mémorandum sur la corrélation [Python]
À propos des opérateurs de comparaison de chaînes Python
À propos de Python et des expressions régulières
À propos des fonctionnalités de Python
À propos de "for _ in range ():" de python
À propos des opérations Python et OS
Python # À propos de la référence et de la copie
À propos de Python sort () et reverse ()
Une note sur [python] __debug__
Remarque Python: à propos de la comparaison en utilisant is
À propos de l'installation des séries Pwntools et Python2
Python: une note sur les classes 1 "Résumé"
[Python] Écrivons brièvement la notation d'inclusion
Déboguer un programme multi-processus python avec VSCode
À propos de Python dict et des fonctions triées
À propos de Python et Cython dtype
[Python] Qu'est-ce que @? (À propos des décorateurs)
Ce qui était surprenant dans les classes Python
À propos de Python Pickle (cPickle) et Marshal
[Python] À propos des classes Executor et Future
À propos de la liste de base des bases de Python
Une note sur mock (bibliothèque fictive Python)
python kafka
À propos de LangID
À propos de CAGR