web-dev-qa-db-fra.com

Exécuter Python sur plusieurs cœurs

J'ai créé un (assez grand) programme qui prend assez de temps à terminer et j'ai commencé à chercher des moyens d'accélérer le programme.

J'ai constaté que si j'ouvre le gestionnaire de tâches pendant que le programme s'exécute, un seul cœur est utilisé.

Après quelques recherches, j'ai trouvé ce site Web: Pourquoi le multitraitement n'utilise-t-il qu'un seul cœur après avoir importé numpy? qui donne une solution de os.system("taskset -p 0xff %d" % os.getpid()), mais cela ne fonctionne pas pour moi et mon programme continue de fonctionner sur un seul cœur.

J'ai ensuite trouvé ceci: est python capable de fonctionner sur plusieurs cœurs? , ce qui pointait vers l'utilisation du multitraitement.

Donc, après avoir étudié le multitraitement, je suis tombé sur ce documentaire sur la façon de l'utiliser https://docs.python.org/3/library/multiprocessing.html#examples

J'ai essayé le code:

from multiprocessing import Process

def f(name):
    print('hello', name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

a = input("Finished")

Après avoir exécuté le code (pas en IDLE), il a dit ceci:

Finished
hello bob
Finished

Remarque: après avoir dit Terminé la première fois que j'ai appuyé sur Entrée

Donc, après cela, je suis encore plus confus et j'ai deux questions

Premièrement: il ne fonctionne toujours pas avec plusieurs cœurs (j'ai un Intel i7 à 8 cœurs)

Deuxièmement: pourquoi saisit-il "Terminé" avant même d'exécuter le code d'instruction if (et il n'est même pas encore terminé!)

8
Ruler Of The World

Pour répondre à votre deuxième question en premier, "Terminé" est imprimé sur le terminal car a = input("Finished") est en dehors de votre if __name__ == '__main__': bloc de code. Il s'agit donc d'une constante de niveau de module qui est affectée lors du premier chargement du module et s'exécute avant l'exécution de tout code du module.

Pour répondre à la première question, vous n'avez créé qu'un seul processus que vous exécutez, puis attendez de terminer avant de continuer. Cela vous donne zéro avantages du multitraitement et entraîne des frais généraux de création du nouveau processus.

Parce que vous voulez créer plusieurs processus, vous devez créer un pool via une collection quelconque (par exemple une liste python), puis démarrer tous les processus.

En pratique, vous devez vous préoccuper de plus que le nombre de processeurs (comme la quantité de mémoire disponible, la possibilité de redémarrer les travailleurs qui plantent, etc.). Cependant, voici un exemple simple qui termine votre tâche ci-dessus.

import datetime as dt
from multiprocessing import Process, current_process
import sys

def f(name):
    print('{}: hello {} from {}'.format(
        dt.datetime.now(), name, current_process().name))
    sys.stdout.flush()

if __name__ == '__main__':
    worker_count = 8
    worker_pool = []
    for _ in range(worker_count):
        p = Process(target=f, args=('bob',))
        p.start()
        worker_pool.append(p)
    for p in worker_pool:
        p.join()  # Wait for all of the workers to finish.

    # Allow time to view results before program terminates.
    a = input("Finished")  # raw_input(...) in Python 2.

Notez également que si vous rejoignez des collaborateurs immédiatement après leur démarrage, vous attendez que chaque collaborateur termine sa tâche avant de démarrer le suivant. Cela n'est généralement pas souhaitable, sauf si l'ordre des tâches doit être séquentiel.

Typiquement incorrect

worker_1.start()
worker_1.join()

worker_2.start()  # Must wait for worker_1 to complete before starting worker_2.
worker_2.join()

Habituellement souhaité

worker_1.start()
worker_2.start()  # Start all workers.

worker_1.join()
worker_2.join()   # Wait for all workers to finish.

Pour plus d'informations, veuillez vous référer aux liens suivants:

12
Alexander