multiprocessing.Pool() langsamer als nur mit normalen Funktionen

(Diese Frage ist über, wie man multiprocessing.Pool() code ausführen schneller. Ich schließlich löste es sich, und die endgültige Lösung kann gefunden werden an der Unterseite der post.)

Ursprünglichen Frage:

Ich versuche, Python zu vergleichen, ein Wort mit vielen anderen Worten in einer Liste und rufen Sie eine Liste der wichtigsten ähnlichen. Zu tun, dass ich die difflib.get_close_matches Funktion. Ich bin auf einem relativ neuen und leistungsstarken Windows 7-Laptop-computer mit Python 2.6.5.

Was ich will, ist die Beschleunigung des Prozesses Vergleich, da meine Vergleichs-Liste von Wörtern ist sehr lang und ich muss wiederholen Sie den Vergleich Vorgang mehrmals. Als ich hörte, über das multiprocessing-Modul erschien es mir logisch, dass, wenn der Vergleich könnte aufgeteilt werden in worker-tasks gleichzeitig laufen (und damit die Nutzung der Maschine macht im Austausch für eine schnellere Geschwindigkeit) mein Vergleich Aufgabe fertig würde, schneller.

Jedoch, selbst nachdem Sie versucht, viele verschiedene Möglichkeiten und Methoden, die gezeigt worden sind, in die docs und schlug vor, im forum Beiträge, die Pool-Methode scheint einfach unglaublich langsam, viel langsamer als nur mit der original-get_close_matches-Funktion auf die gesamte Liste auf einmal. Ich möchte helfen zu verstehen, warum Pool() so langsam ist und ob ich es richtig. Ich bin nur mit diesem string-Vergleich Szenario als Beispiel, denn das ist das jüngste Beispiel, das ich denken konnte, wo ich war nicht in der Lage zu verstehen oder zu bekommen multiprocessing zu arbeiten anstatt gegen mich. Unten ist nur ein Beispiel-code aus dem difflib Szenario zeigt die Zeit an, die Unterschiede zwischen der normalen und der Zusammengefassten Methoden:

from multiprocessing import Pool
import random, time, difflib

# constants
wordlist = ["".join([random.choice([letter for letter in "abcdefghijklmnopqersty"]) for lengthofword in xrange(5)]) for nrofwords in xrange(1000000)]
mainword = "hello"

# comparison function
def findclosematch(subwordlist):
    matches = difflib.get_close_matches(mainword,subwordlist,len(subwordlist),0.7)
    if matches <> []:
        return matches

# pool
print "pool method"
if __name__ == '__main__':
    pool = Pool(processes=3)
    t=time.time()
    result = pool.map_async(findclosematch, wordlist, chunksize=100)
    #do something with result
    for r in result.get():
        pass
    print time.time()-t

# normal
print "normal method"
t=time.time()
# run function
result = findclosematch(wordlist)
# do something with results
for r in result:
    pass
print time.time()-t

Das Wort zu finden ist "Hallo", und die Liste der Wörter, in denen zu finden, die engen Spiele ist ein 1-Millionen-lange Liste von 5 zufällig trat Zeichen (nur zur illustration). Ich benutze 3 Prozessorkerne und die map-Funktion mit einer chunksize von 100 (listitems werden procesed pro Arbeiter, die ich denke??) (Ich habe auch versucht chunksizes von 1000 und 10 000, aber es gab keinen wirklichen Unterschied). Beachten Sie, dass in beiden Methoden, die ich starten Sie den timer direkt vor dem Aufruf meine Funktion und beenden Sie es gleich nach Ihrer durchgeschleift der Ergebnisse. Wie Sie unten sehen können das timing die Ergebnisse sind deutlich zu Gunsten der ursprünglichen nicht-Pool-Methode:

>>> 
pool method
37.1690001488 seconds
normal method
10.5329999924 seconds
>>> 

Pool-Methode ist fast 4 mal langsamer, als die ursprüngliche Methode. Gibt es etwas, was ich hier vermisst, oder vielleicht auch Missverständnisse darüber, wie die Bündelung/multiprocessing funktioniert? Ich mache vermuten, dass ein Teil des problem hier könnte sein, dass die map-Funktion gibt Keine, und so fügt Tausende von unnötige Elemente, um die resultslist obwohl ich will nur aktuelle Spiele zurückgegeben werden, um die Ergebnisse und geschrieben haben, es als solches in der Funktion. Von dem was ich verstehe, ist nur, wie die Karte funktioniert. Ich habe gehört, über ein paar andere Funktionen, wie filter, der nur sammelt, nicht-Falsche Ergebnisse, aber ich denke, dass die multiprocessing - /Pool-unterstützt den filter-Methode. Gibt es noch andere Funktionen außer der Karte/imap in das multiprocessing-Modul, das helfen könnte, mich in die nur das zurück, was meine Funktion gibt? Anwenden, Funktion ist mehr für die Angabe von mehreren Argumenten, wie ich Sie verstehe.

Ich weiß, es gibt auch die imap-Funktion, die ich versucht, aber ohne Zeit-Verbesserungen. Der Grund dafür ist der gleiche Grund, warum ich habe Probleme zu verstehen, was ist so toll an dem itertools-Modul, angeblich "blitzschnell", die ich bemerkt habe, ist wahr für den Aufruf der Funktion, aber in meiner Erfahrung und von dem, was ich gelesen habe, dass die da rufen Sie die Funktion eigentlich nicht für Berechnungen, also wenn es Zeit zu Durchlaufen und die Ergebnisse zu sammeln und zu analysieren (ohne die es keinen Sinn hätte, den Aufruf der cuntion) es braucht genauso viel oder manchmal auch mehr Zeit als nur mit der normalen version der Funktion straightup. Aber ich nehme an, dass ist für einen anderen post.

Jedenfalls gespannt zu sehen, wenn jemand stupst mich in die richtige Richtung, und wirklich dankbar für jede Hilfe auf diesem. Ich bin mehr daran interessiert, Verständnis multiprocessing im Allgemeinen als um dieses Beispiel funktioniert, aber es wäre nützlich, einige Beispiel-Lösung code-Vorschläge, um Hilfe in meinem Verständnis.

Die Antwort:

Scheint, wie die Abkühlung hatte zu tun mit dem langsamen Systemstart von zusätzlichen Prozessen. I couldnt get .Pool () - Funktion, um schnell genug sein. Meine Letzte Lösung um es schneller zu machen war, um manuell aufteilen der Arbeitslast Liste, verwenden Sie mehrere .Process() statt .Pool () und schicken Sie die Lösungen in einer Warteschlange. Aber ich Frage mich, ob vielleicht die wichtigste Veränderung war die Aufteilung der Arbeitsbelastung in Bezug auf die Haupt-Wort zu suchen, anstatt die Wörter zu vergleichen, mit, vielleicht, weil die difflib Suchfunktion ist schon so schnell. Hier ist der neue code laufen 5 Prozesse gleichzeitig, und stellte sich heraus, über x10 schneller als das ausführen einer einfachen code (6 Sekunden vs 55 Sekunden). Sehr nützlich für schnelle fuzzy-Abfragen, die auf der Oberseite wie schnell difflib schon ist.

from multiprocessing import Process, Queue
import difflib, random, time

def f2(wordlist, mainwordlist, q):
    for mainword in mainwordlist:
        matches = difflib.get_close_matches(mainword,wordlist,len(wordlist),0.7)
        q.put(matches)

if __name__ == '__main__':

    # constants (for 50 input words, find closest match in list of 100 000 comparison words)
    q = Queue()
    wordlist = ["".join([random.choice([letter for letter in "abcdefghijklmnopqersty"]) for lengthofword in xrange(5)]) for nrofwords in xrange(100000)]
    mainword = "hello"
    mainwordlist = [mainword for each in xrange(50)]

    # normal approach
    t = time.time()
    for mainword in mainwordlist:
        matches = difflib.get_close_matches(mainword,wordlist,len(wordlist),0.7)
        q.put(matches)
    print time.time()-t

    # split work into 5 or 10 processes
    processes = 5
    def splitlist(inlist, chunksize):
        return [inlist[x:x+chunksize] for x in xrange(0, len(inlist), chunksize)]
    print len(mainwordlist)/processes
    mainwordlistsplitted = splitlist(mainwordlist, len(mainwordlist)/processes)
    print "list ready"

    t = time.time()
    for submainwordlist in mainwordlistsplitted:
        print "sub"
        p = Process(target=f2, args=(wordlist,submainwordlist,q,))
        p.Daemon = True
        p.start()
    for submainwordlist in mainwordlistsplitted:
        p.join()
    print time.time()-t
    while True:
        print q.get()

InformationsquelleAutor der Frage Karim Bahgat | 2013-12-22

Schreibe einen Kommentar