Python, en utilisant des serveurs multi-processus est plus lent que ne l'utilisez pas
Après avoir passé beaucoup de temps à essayer d'envelopper ma tête autour de multitraitement je suis venu avec ce code, qui est un test de référence:
Exemple 1:
from multiprocessing import Process
class Alter(Process):
def __init__(self, word):
Process.__init__(self)
self.word = word
self.word2 = ''
def run(self):
# Alter string + test processing speed
for i in range(80000):
self.word2 = self.word2 + self.word
if __name__=='__main__':
# Send a string to be altered
thread1 = Alter('foo')
thread2 = Alter('bar')
thread1.start()
thread2.start()
# wait for both to finish
thread1.join()
thread2.join()
print(thread1.word2)
print(thread2.word2)
Ceci termine en 2 secondes (la moitié du temps de multithreading). Par curiosité j'ai décidé de lancer cette prochaine:
Exemple 2:
word2 = 'foo'
word3 = 'bar'
word = 'foo'
for i in range(80000):
word2 = word2 + word
word = 'bar'
for i in range(80000):
word3 = word3 + word
print(word2)
print(word3)
À ma grande horreur, ce couru en moins d'une demi-seconde!
Ce qui se passe ici? Je m'attendais à le multitraitement de courir plus vite - ne devrait-elle pas complète dans la moitié de l'Exemple 2 du temps étant donné que l'Exemple 1 est l'Exemple 2, divisé en deux processus?
Mise à jour:
Après avoir tenu compte de Chris commentaires, j'ai compris le "réel" code consomment le plus de temps de traitement, et m'amène à considérer le multitraitement:
self.ListVar = [[13379+ strings],[13379+ strings],
[13379+ strings],[13379+ strings]]
for b in range(len(self.ListVar)):
self.list1 = []
self.temp = []
for n in range(len(self.ListVar[b])):
if not self.ListVar[b][n] in self.temp:
self.list1.insert(n, self.ListVar[b][n] + '(' +
str(self.ListVar[b].count(self.ListVar[b][n])) +
')')
self.temp.insert(0, self.ListVar[b][n])
self.ListVar[b] = list(self.list1)
OriginalL'auteur Rhys | 2012-01-08
Vous devez vous connecter pour publier un commentaire.
ETA: Maintenant que vous avez posté votre code, je peux vous dire qu'il y est un moyen simple de faire ce que vous êtes en train de faire BEAUCOUP plus rapidement (>100 fois plus rapide).
Je vois que ce que vous faites est l'ajout d'une fréquence entre parenthèses pour chaque élément dans une liste de chaînes de caractères. Au lieu de compter tous les éléments à chaque fois (ce qui, comme vous pouvez le confirmer à l'aide de cProfile, est de loin le plus important goulot d'étranglement dans votre code), vous pouvez simplement créer un dictionnaire que les cartes de chaque élément à sa fréquence. De cette façon, vous n'avez qu'à aller dans la liste deux fois - une fois pour créer la fréquence dictionnaire, une fois de l'utiliser pour ajouter de la fréquence.
Ici, je vais vous montrer ma nouvelle méthode, le temps, et de le comparer à l'ancienne méthode, à l'aide d'un cas de test générée. Le cas de test montre même le nouveau résultat à exactement identique à l'ancien. Remarque: Tous vous avez vraiment besoin de faire attention à ci-dessous est la new_method.
Lorsque je l'exécute, il devient temps de (15.963812112808228, 0.05961179733276367), c'est environ 250 fois plus rapide, bien que cet avantage dépend de combien de temps les listes et la distribution de fréquence à l'intérieur de chaque liste. Je suis sûr que vous serez d'accord que, avec cet avantage de vitesse, vous n'aurez probablement pas besoin d'utiliser le multitraitement 🙂
(Ma réponse originale à cette question est de gauche ci-dessous pour la postérité)
ETA: Par ailleurs, il est intéressant de noter que cet algorithme est à peu près linéaire en la longueur de la liste, tandis que le code utilisé est quadratique. Cela signifie qu'il effectue avec encore plus de l'avantage le plus grand nombre d'éléments. Par exemple, si vous augmentez la longueur de chaque liste à 1000000, il ne prend que 5 secondes pour s'exécuter. Basée sur l'extrapolation, l'ancien code fallu attendre plus d'une journée 🙂
Il dépend de l'opération que vous effectuez. Par exemple:
Sur ma machine, le multiprocessed opération prend seulement environ 60% du temps de la single thread.
Dans les deux mon code et le vôtre, il ne prend en compte que les cordes de chaque liste (pas dans l'ensemble, la liste imbriquée). Notez que la fréquence dictionnaire est recréé à chaque inner_lst. Aussi, vous montrer "sam(2)", tel qu'il apparaît deux fois dans votre exemple ici, mais la façon dont vous avez écrit le code, où il vérifie la température de la matrice de ceux qui existent déjà, il semblerait qu'une seule fois: [['betty(1)', 'harry(1)', 'sam(2)'], ['gary(1)', 'larry(1)', 'de la fed(1)', 'sam(1)']]. Les deux ma méthode et la vôtre en retour.
ok merci, votre droit sur le temp de chose qu'il ne devrait être qu'1 sam(2), je vais revérifier qu'il compte correctement de nouveau quand je serai de retour à la maison
oui, vous avez raison. tous les doublons sont supprimés, je ne pouvais pas en trouver un qui est exactement ce dont j'avais besoin. Merci beaucoup
OriginalL'auteur David Robinson
Cet exemple est trop petite pour bénéficier de multitraitement.
Il y a BEAUCOUP de surcharge lors du démarrage d'un nouveau processus. Si il y avait de lourdes de traitement impliqués, il serait négligeable. Mais votre exemple n'est vraiment pas intensive, et donc, vous êtes lié pour avis de la surcharge.
Vous auriez sans doute remarqué une grande différence avec de vrais fils, trop mauvais python (bien, Disponible) a des problèmes avec le CPU threading.
eh bien pour une chose que vous avez vous-même un exemple qui vient mange et mange de la mémoire, qui est lié à causer des problèmes. Réel lié au PROCESSEUR de traitement de code serait comme, je sais pas, la matrice de décomposition ou de quelque chose.
Je suis en essais pour les éléments suivants de l'application. Pour demander une liste de chaînes de caractères (une liste de 17000 chaînes de caractères), si (chaque) les entrées en double. et Si oui, pour ajouter que l'entrée de la chaîne avec le nombre de doublons entre parenthèses ... dois-je utiliser le multitraitement pour cela?
Rhys: vous devriez peut-être poster un extrait de votre code? Il y a peut être d'autres optimisations de performances pourrait nous laisser croire.
permettez-moi de vous donner la plus importante pièce de conseils jamais donné à moi-même: quand il s'agit de l'optimisation, de mesurer, mesurer, mesurer à nouveau. Sauf si vous commencez à courir profileurs de voir exactement où le goulot d'étranglement qui se passe, c'est que spéculation. Les processus n'ont plus de ressources que les threads. C'est un fait. Cependant, je ne peux pas dire avec 100% de confiance quel en sera l'impact de votre code.
OriginalL'auteur Chris Eberle
Multitraitement pourrait être utile pour ce que vous faites, mais pas dans la façon dont vous pensez à l'utiliser. Que vous êtes essentiellement faire quelques calculs sur chaque membre de une liste, vous pouvez le faire en utilisant le
multiprocessing.Pool.map
méthode, pour faire le calcul sur la liste des membres en parallèle.Voici un exemple qui montre votre code de la performance à l'aide d'un processus unique et à l'aide de
multiprocessing.Pool.map
:De sortie:
pas de problème 😉 dès que cela a été utile, j'en suis heureux. (vous pouvez donner des points à plusieurs réponses, mais vous ne pouvez choisir l'un que LA réponse)
yep, j'ai voté pour assurer
C'est une très bonne idée en général, et quelque chose que chaque novice à
multiprocessing
doit être exposé à la dès que possible... mais il ne fait pas l'adresse de son problème. Il avait déjà la moitié du travail qui est fait sur chaque processus; à moins que les tâches sont très variable dans le temps nécessaire (ce qui ils ne sont pas dans votre exemple, ou son), l'ajout d'une piscine ajoute juste un peu de surcharge. Il peut encore être utile de faire pour des raisons de lisibilité et d'organisation, mais il n'est pas pour des raisons de performances. (Encore une fois, ce n'est pas vrai pour tous les problèmes, juste comme ça.)OriginalL'auteur mdeous
Ce fil de discussion a été très utile!
Juste une petite observation sur la bonne deuxième code fourni par David Robinson ci-dessus (réponse Jan 8 '12 à 5:34), qui est le code plus adapté à mes besoins actuels.
Dans mon cas, j'ai eu les précédents records du temps d'exécution d'une fonction cible sans multiprocessing. Lors de l'utilisation de son code, de mettre en œuvre un traitement multiple fonction de son timefunc(multi) n'ont pas tenu compte de la durée réelle du multi, et il semblent plutôt refléter le temps qui leur est consacré dans le parent.
Ce que j'ai fait a été à l'externalisation de la fonction de chronométrage et le temps que j'ai regardé de plus comme prévu:
Dans mon cas, avec un double cœur, le temps total est effectuée par 'x' ouvriers à l'aide de la fonction cible a été deux fois plus rapide que l'exécution d'une simple boucle for-dessus de la cible de la fonction " x " des itérations.
Je suis nouveau sur le multitraitement il vous faut donc être prudent avec cette observation.
timeit
de la bibliothèque de la bonne façon de mesurer l'horloge murale prises par votre code, mais brièvement:elapsed = timeit.timeit(multi, number=100, repeat=3)
sera assurez-vous d'utiliser le droit de la fonction horloge, prendre soin des choses que vous ne pensez pas, comme la désactivation de la GC détecteur de cycle, l'exécution de votre code 100 fois, répétez le test 3 fois et prendre la valeur la plus basse de sorte que vous pouvez être sûr qu'il n'y avait pas d'externalités interférant avec le calendrier, etc.OriginalL'auteur user3675901