Traitement parallèle sans signification profonde en Python

Lors de la résolution du puzzle de code sur un certain site, je ne pouvais pas du tout penser à une solution, alors j'ai décidé d'essayer le rond-point interdit.

Le problème est de trouver m pour lequel f (m) == c pour une fonction f et une constante c données.

Tout d'abord, simplement

Le résultat de l'implémentation sans réfléchir pour le moment est le code suivant.

solution1


import sys

def solve(m):
    # f,c est défini
    return f(m) == c

def solution1():
    limit = int(sys.argv[1])
    ans = [m for m in range(limit) if solve(m)]
    print ans

Je me suis demandé combien de temps le temps de traitement prendrait, alors j'ai préparé un profileur.

profile


import cProfile

if __name__ == '__main__':
    profiler = cProfile.Profile()
    profiler.runcall(solution1)
    profiler.print_stats()

Et courir.

solution1_profile_result


% python mp.py 100000000

(La solution est omise)

200000003 function calls in 333.009 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
100000000   78.739    0.000  299.934    0.000 mp.py:12(solve)
        1   30.856   30.856  333.009  333.009 mp.py:31(solution1)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
100000000  221.195    0.000  221.195    0.000 {pow}
        1    2.219    2.219    2.219    2.219 {range}

Ventilé, parallèle et ...

Quand je me demandais si je connaissais la réponse pour le moment, j'ai entendu une voix venant du côté disant: "Pourquoi ne pas paralléliser www bufefe www?" En pensant "Au fait, je n'ai jamais étudié le traitement parallèle de Python", je vais implémenter une version parallélisée.

solution2


import math
import sys
from multiprocessing import Process, Queue


def task(q, num_range):
    #Pour transmettre des données au côté principal via la file d'attente,Il n'y a pas de signification essentielle dans ce programme.
    #Mirita Cutter Ducker
    q.put([m for m in num_range if solve(m)])


def solution2():
    queue = Queue()
    limit = int(sys.argv[1])
    worker_num = int(sys.argv[2])
    task_size = int(math.ceil(float(limit) / float(worker_num)))

    #Divisez la liste à traiter,Passer à chaque processus.
    # ref. http://iogi.hatenablog.com/entry/split-list-into-sublist
    num_ranges = izip_longest(*[iter(range(limit))]*task_size)
    processes = [Process(group=None, target=task, args=(queue, num_range))
                 for num_range in num_ranges]

    for process in processes:
        process.start()

    for process in processes:
        print queue.get()
        process.join()

Et le temps de traitement est presque de moitié.

solution2_profile_result


% python mp.py 100000000 4

(La solution est omise)

1021 function calls (1018 primitive calls) in 182.498 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 __future__.py:48(<module>)
        1    0.000    0.000    0.000    0.000 __future__.py:74(_Feature)
        7    0.000    0.000    0.000    0.000 __future__.py:75(__init__)
        1    0.005    0.005    0.042    0.042 __init__.py:102(Pipe)
        1    0.004    0.004    0.084    0.084 __init__.py:213(Queue)
        1    0.000    0.000    0.000    0.000 connection.py:117(Listener)
        1    0.000    0.000    0.000    0.000 connection.py:183(Pipe)
        1    0.000    0.000    0.000    0.000 connection.py:246(SocketListener)
        1    0.013    0.013    0.037    0.037 connection.py:35(<module>)
        1    0.000    0.000    0.000    0.000 connection.py:426(ConnectionWrapper)
        1    0.000    0.000    0.000    0.000 connection.py:448(XmlListener)
        1    0.000    0.000    0.000    0.000 forking.py:113(Popen)
        4    0.000    0.000    0.027    0.007 forking.py:115(__init__)
       (Abréviation)

Mémoire avancée

L'implémentation précédente utilise la fonction de plage pour générer une liste lors de la division d'une liste. Par conséquent, l'utilisation de la mémoire est excellente.

solution2.png

Ce problème a été résolu en utilisant la fonction xrange au lieu de la fonction range. La fonction xrange renvoie un itérateur au lieu d'une liste, elle ne consomme donc pas de mémoire en même temps.

solution3


import math
import sys
from multiprocessing import Process, Queue


def solution3():
    queue = Queue()
    limit = int(sys.argv[1])
    worker_num = int(sys.argv[2])
    task_size = int(math.ceil(float(limit) / float(worker_num)))

    gen = xrange(limit)
    processes = [Process(
                 group=None,
                 target=task,
                 args=(queue, islice(gen, task_size * i, task_size * (i + 1))))
                 for i in xrange(worker_num)]

    for process in processes:
        process.start()

    for process in processes:
        print queue.get()
        process.join()

Donc, exécution + consommation de mémoire à ce moment-là. Le temps d'exécution n'a guère changé, mais la consommation de mémoire a considérablement diminué.

solution3_profile_result


% python mp.py 100000000 4

(La solution est omise)

1019 function calls (1016 primitive calls) in 187.432 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 __future__.py:48(<module>)
        1    0.000    0.000    0.000    0.000 __future__.py:74(_Feature)
        7    0.000    0.000    0.000    0.000 __future__.py:75(__init__)
        1    0.006    0.006    0.047    0.047 __init__.py:102(Pipe)
        1    0.005    0.005    0.082    0.082 __init__.py:213(Queue)
        1    0.000    0.000    0.000    0.000 connection.py:117(Listener)
        1    0.000    0.000    0.000    0.000 connection.py:183(Pipe)
        1    0.000    0.000    0.000    0.000 connection.py:246(SocketListener)
        1    0.015    0.015    0.041    0.041 connection.py:35(<module>)
        1    0.000    0.000    0.000    0.000 connection.py:426(ConnectionWrapper)
        1    0.000    0.000    0.000    0.000 connection.py:448(XmlListener)
        1    0.000    0.000    0.000    0.000 forking.py:113(Popen)
        4    0.000    0.000    0.001    0.000 forking.py:115(__init__)
       10    0.000    0.000    0.000    0.000 forking.py:130(poll)
        4    0.000    0.000    0.000    0.000 forking.py:146(wait)
        1    0.014    0.014    0.019    0.019 forking.py:35(<module>)
       (Abréviation)

solution3.png

(Supplément) Différence de fonction de plage en Python 2/3

En Python3, la fonction range renvoie un itérateur appelé classe range, donc la correspondance ci-dessus n'est pas nécessaire. Au contraire, la fonction xrange est obsolète.

// Python3
% python3
  Python 3.3.0 (default, Mar  2 2013, 11:44:00)
  [GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.24)] on darwin
  Type "help", "copyright", "credits" or "license" for more information.
  >>> a = range(5)
  >>> a
  range(0, 5)
  >>> type(a)
  <class 'range'>
  >>>
  >>> xrange(5)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'xrange' is not defined

// Python2
% python
  Python 2.7.3 (default, May 14 2012, 22:41:33)
  [GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)] on darwin
  Type "help", "copyright", "credits" or "license" for more information.
  >>> a = range(5)
  >>> a
  [0, 1, 2, 3, 4]
  >>> type(a)
  <type 'list'>
  >>>

Recommended Posts

Traitement parallèle sans signification profonde en Python
[Python] Traitement parallèle facile avec Joblib
Lire des fichiers en parallèle avec Python
Traitez facilement des images en Python avec Pillow
Traitement de fichiers en Python
Comment faire un traitement parallèle multicœur avec python
Traitement multithread en python
Téléchargement parallèle avec Python
Création d'un fichier exe avec Python PyInstaller: le PC se fige dans le traitement parallèle
Traitement des requêtes en Python
Python: apprentissage profond du traitement du langage naturel: principes de base
Traitement d'image avec Python
Recevez une liste des résultats du traitement parallèle en Python avec starmap
Traitement parallèle avec multitraitement
Introduction au traitement parallèle distribué Python par Ray
Traitement d'image avec Python (partie 2)
100 coups de traitement du langage avec Python 2015
Traitement de texte UTF8 avec python
Traitement parallèle avec des fonctions locales
Grattage au sélénium en Python
"Traitement Apple" avec OpenCV3 + Python3
Exploitez LibreOffice avec Python
Grattage avec chromedriver en python
Débogage avec pdb en Python
Exécuter Python unittest en parallèle
Traitement du signal acoustique avec Python (2)
Traitement du signal acoustique avec Python
Gérer les sons en Python
Grattage avec du sélénium en Python
Traitement asynchrone (threading) en python
Traitement parallèle avec Parallel de scikit-learn
Traitement d'image avec Python (partie 1)
Grattage avec Tor en Python
Tweet avec image en Python
Combiné avec ordinal en Python
Traitement d'image avec Python (3)
Collection de traitement d'image en Python
Utilisation du mode Python dans le traitement
[Python] Traitement d'image avec scicit-image
Reconnaissance des nombres dans les images avec Python
Tester avec des nombres aléatoires en Python
Traitement parallèle Python (multitraitement et Joblib)
GOTO en Python avec Sublime Text 3
Travailler avec LibreOffice en Python: import
100 traitements de langage avec Python
Scraping avec Selenium en Python (Basic)
100 Language Processing Knock Chapitre 1 en Python
Analyse CSS avec cssutils en Python
Numer0n avec des objets fabriqués avec Python
Ouvrez UTF-8 avec BOM en Python
100 traitements de langage avec Python (chapitre 3)
Traitement d'image avec la binarisation Python 100 knocks # 3
Utiliser rospy avec virtualenv dans Python3
Utiliser Python mis en pyenv avec NeoVim
Il n'y a pas de commutateur en python
Résumé de l'exemple de code de traitement parallèle / parallèle Python
Heatmap avec dendrogramme en Python + matplotlib
Générer un mot de passe pour le manuel avec python
Utiliser OpenCV avec Python 3 dans Window
100 traitement d'image par Python Knock # 2 Échelle de gris
Jusqu'à traiter de python dans Atom