web-dev-qa-db-fra.com

Le bloc-notes Jupyter ne termine jamais le traitement à l'aide du multitraitement (Python 3)

enter image description here

Carnet Jupyter

J'utilise essentiellement le module de multiprocessing, j'apprends toujours les capacités du multiprocessing. J'utilise le livre de Dusty Phillips et ce code lui appartient.

import multiprocessing  
import random
from multiprocessing.pool import Pool

def prime_factor(value):
    factors = []
    for divisor in range(2, value-1):
        quotient, remainder = divmod(value, divisor)
        if not remainder:
            factors.extend(prime_factor(divisor))
            factors.extend(prime_factor(quotient))
            break
        else:
            factors = [value]
    return factors

if __name__ == '__main__':
    pool = Pool()
    to_factor = [ random.randint(100000, 50000000) for i in range(20)]
    results = pool.map(prime_factor, to_factor)
    for value, factors in Zip(to_factor, results):
        print("The factors of {} are {}".format(value, factors))

Sur Windows PowerShell (pas sur le portable jupyter), je vois ce qui suit

Process SpawnPoolWorker-5:
Process SpawnPoolWorker-1:
AttributeError: Can't get attribute 'prime_factor' on <module '__main__' (built-in)>

Je ne sais pas pourquoi la cellule ne s'arrête jamais de fonctionner?

13
rsc05

Il semble que le problème dans le cahier Jupyter comme dans une autre idée soit la fonctionnalité de conception. Par conséquent, nous devons écrire la fonction (prime_factor) dans un fichier différent et importer le module. De plus, nous devons nous occuper des ajustements. Par exemple, dans mon cas, j'ai codé la fonction dans un fichier appelé defs.py

def prime_factor(value):
    factors = []
    for divisor in range(2, value-1):
        quotient, remainder = divmod(value, divisor)
        if not remainder:
            factors.extend(prime_factor(divisor))
            factors.extend(prime_factor(quotient))
            break
        else:
            factors = [value]
    return factors

Puis dans le cahier jupyter j'ai écrit les lignes suivantes

import multiprocessing  
import random
from multiprocessing import Pool
import defs



if __name__ == '__main__':
    pool = Pool()
    to_factor = [ random.randint(100000, 50000000) for i in range(20)]
    results = pool.map(defs.prime_factor, to_factor)
    for value, factors in Zip(to_factor, results):
        print("The factors of {} are {}".format(value, factors))

Cela a résolu mon problème

enter image description here

20
rsc05

Pour exécuter une fonction sans avoir à l'écrire manuellement dans un fichier séparé:

Nous pouvons écrire dynamiquement la tâche à traiter dans un fichier temporaire, l'importer et exécuter la fonction.

from multiprocessing import Pool
from functools import partial
import inspect

def parallal_task(func, iterable, *params):

    with open(f'./tmp_func.py', 'w') as file:
        file.write(inspect.getsource(func).replace(func.__name__, "task"))

    from tmp_func import task

    if __name__ == '__main__':
        func = partial(task, params)
        pool = Pool(processes=8)
        res = pool.map(func, iterable)
        pool.close()
        return res
    else:
        raise "Not in Jupyter Notebook"

Nous pouvons alors simplement l'appeler dans une cellule de carnet comme ceci:

def long_running_task(params, id):
    # Heavy job here
    return params, id

data_list = range(8)

for res in parallal_task(long_running_task, data_list, "a", 1, "b"):
    print(res) 

Sortie:

('a', 1, 'b') 0
('a', 1, 'b') 1
('a', 1, 'b') 2
('a', 1, 'b') 3
('a', 1, 'b') 4
('a', 1, 'b') 5
('a', 1, 'b') 6
('a', 1, 'b') 7

Remarque: Si vous utilisez Anaconda et si vous souhaitez voir la progression de la tâche lourde, vous pouvez utiliser print() dans long_running_task(). Le contenu de l'impression sera affiché dans la console Anaconda Prompt.

1
H4dr1en