Exécution parallèle facile avec le sous-processus python

-Je souhaite traiter une grande quantité de données en parallèle. -Je veux utiliser efficacement le CPU car il a de nombreux cœurs. -J'ai essayé d'écrire le script pour le moment, mais je ne peux pas me permettre de le réécrire pour une exécution parallèle.

J'ai fait des recherches sur diverses choses et il me semblait facile d'utiliser subprocess.Popen (), donc j'ai expérimenté.

Article de référence https://qiita.com/HidKamiya/items/e192a55371a2961ca8a4

Environnement d'exécution et exemple de code pour le test de charge

Windows 10 (64bit) Python 3.7.6

Le processeur est Ryzen 9 3950X et c'est l'environnement. タスク マネージャー 2020_06_27 20_15_14.png

Expérimentez avec le code ci-dessous. (Afficher uniquement les deux derniers chiffres de la colonne de nombre de Fibonacci spécifiée par l'argument de ligne de commande.)

fib_sample.py


import sys

def fib(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

if __name__ == "__main__":
    num = int(sys.argv[1])
    result = fib(num)
    print("n = {0}, result % 100 = {1}".format(num, result % 100))

Par exemple, si vous exécutez python fib_sample.py 10000, il affichera n = 10000, résultat% 100 = 75 et quittera.

Exécuter séquentiellement

Tout d'abord, essayez de l'exécuter séquentiellement avec subprocess.run (). Exécutez python avec un argument dans subprocess.run (['python', r". \ Fib_sample.py ", str (500000 + i)]). Si vous modifiez l'argument de ligne de commande de 500000 à 500063 et que vous l'exécutez 64 fois,

batch_sequential.py


from time import time
import subprocess

start=time()

loop_num = 64
for i in range(loop_num):
    subprocess.run(['python', r".\fib_sample.py", str(500000 + i)])

end=time()
print("%f sec" %(end-start))
> python .\batch_sequential.py
n = 500000, result % 100 = 25
n = 500001, result % 100 = 26
n = 500002, result % 100 = 51
(Omis)
n = 500061, result % 100 = 86
n = 500062, result % 100 = 31
n = 500063, result % 100 = 17
130.562213 sec

Cela a pris un peu plus de deux minutes. De toute évidence, le cœur du processeur n'est pas du tout utilisé. タスク マネージャー 2020_06_27 20_12_28.png

Exécution parallèle

Essayez d'exécuter le même processus en parallèle avec subprocess.Popen (). Contrairement à subprocess.run (), subprocess.Popen () n'attend pas la fin du processus généré. Le code suivant répète l'exécution du processus → attendez qu'ils se terminent tous → la prochaine exécution du processus → ... pour le nombre spécifié par max_process.

batch_parallel.py


from time import time
import subprocess

start=time()

#Nombre maximum d'exécutions de processus parallèles
max_process = 16
proc_list = []

loop_num = 64
for i in range(loop_num):
    proc = subprocess.Popen(['python', r".\fib_sample.py", str(500000 + i)])
    proc_list.append(proc)
    if (i + 1) % max_process == 0 or (i + 1) == loop_num:
        #max_Attendez la fin de tous les processus pour chaque processus
        for subproc in proc_list:
            subproc.wait()
        proc_list = []

end=time()
print("%f sec" %(end-start))

Le résultat de l'exécution de 16 en parallèle selon le nombre de cœurs physiques du Ryzen 3950X.

> python .\batch_parallel.py
n = 500002, result % 100 = 51
n = 500004, result % 100 = 28
n = 500001, result % 100 = 26
(Omis)
n = 500049, result % 100 = 74
n = 500063, result % 100 = 17
n = 500062, result % 100 = 31
8.165289 sec

Comme ils sont exécutés en parallèle, l'ordre dans lequel le traitement se termine est dans le désordre. C'était presque 16 fois plus rapide de 130,562 secondes à 8,165 secondes.

Vous pouvez voir que tous les cœurs sont utilisés et qu'ils sont correctement exécutés en parallèle. タスク マネージャー 2020_06_27 20_22_37.png

En passant, il n'est pas rapide d'exécuter 32 en parallèle en fonction du nombre de cœurs logiques au lieu du nombre de cœurs physiques. Parfois, il se fait tard. Le graphique ci-dessous montre le temps d'exécution moyen lorsque le nombre d'exécutions parallèles est modifié et exécuté trois fois chacune. プレゼンテーション1.png J'ai utilisé diverses applications en arrière-plan, donc ce n'est pas très précis, mais je pense que la tendance est correcte.

Résumé

C'était assez facile à accélérer. Avec le code ci-dessus, après le démarrage de l'exécution parallèle, il attend la fin du processus avec le temps de traitement le plus long, donc s'il y a un processus avec un temps de traitement long, la surcharge liée à l'attente de la fin de ce processus augmentera. À l'origine, je pense que le code devrait démarrer le processus suivant dès que chaque processus a fini de s'exécuter et créer le code de sorte que le nombre de parallèles soit toujours constant. Cependant, en réalité, le but était d'accélérer les applications telles que l'application d'un grand nombre de fichiers de données de même longueur au même traitement du signal, alors j'ai fermé les yeux en espérant que le temps d'exécution serait à peu près le même. Pour le moment, j'étais satisfait car j'ai pu facilement atteindre l'objectif d'accélération.

Recommended Posts

Exécution parallèle facile avec le sous-processus python
[Python] Traitement parallèle facile avec Joblib
[Analyse de co-occurrence] Analyse de co-occurrence facile avec Python! [Python]
Synchronisation facile des dossiers avec Python
Mesure du temps d'exécution avec Python avec
Compilation facile de Python avec NUITKA-Utilities
Serveur HTTP facile avec Python
mémorandum d'exécution parallèle / asynchrone python
Programmation facile Python + OpenCV avec Canopy
Optimisation bayésienne très simple avec Python
Lire des fichiers en parallèle avec Python
Visualisez facilement vos données avec Python seaborn.
Extraction de mots-clés facile avec TermExtract pour Python
[Python] Test super facile avec instruction assert
[Python] Vérification simple du type d'argument avec la classe de données
Introduction facile de la reconnaissance vocale avec Python
[Easy Python] Lecture de fichiers Excel avec openpyxl
Traitez facilement des images en Python avec Pillow
[Easy Python] Lecture de fichiers Excel avec des pandas
Scraping Web facile avec Python et Ruby
Exécution de tâches parallèles à l'aide de concurrent.futures en Python
[Python] Essayez facilement l'apprentissage amélioré (DQN) avec Keras-RL
FizzBuzz en Python3
Grattage avec Python
Python est facile
Statistiques avec python
Grattage avec Python
Python avec Go
Twilio avec Python
Intégrer avec Python
Jouez avec 2016-Python
AES256 avec python
Testé avec Python
python commence par ()
avec syntaxe (Python)
Bingo avec python
Zundokokiyoshi avec python
Excel avec Python
Micro-ordinateur avec Python
Cast avec python
[Python] Introduction facile à l'apprentissage automatique avec python (SVM)
Préparer l'environnement d'exécution de Python3 avec Docker
Quittez l'exécution de Python avec Ctrl-C (répond à SIGINT)
Comment mesurer le temps d'exécution avec Python Partie 1
Traitement parallèle sans signification profonde en Python
Analyse de régression LASSO facile avec Python (pas de théorie)
Créer un environnement d'exécution python avec VS Code
Comment mesurer le temps d'exécution avec Python, partie 2
✨ Facile avec Python ☆ Temps écoulé estimé après la mort ✨
Communication série avec Python
Zip, décompressez avec python
Django 1.11 a démarré avec Python3.6
Jugement des nombres premiers avec Python
Communication de socket avec Python
Analyse de données avec python 2
Easy Grad-CAM avec pytorch-gradcam
Essayez de gratter avec Python.
Apprendre Python avec ChemTHEATER 03