Seite 1 von 1

Multiprocessing immer gleich langsam

Verfasst: Sonntag 20. Februar 2022, 16:39
von CptK
Hallo zusammen, ich versuche mich gerade mal an multiprocessing und habe dafür folgendes (nutzloses) Beispiel, das einfach die Summe einer Liste berechnet:

Code: Alles auswählen

import time
import multiprocessing as mp
import sys

def split(data, n):
    k, m = divmod(len(data), n)
    return list(data[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(n))

def my_func(x):
    print(len(x))
    for i in range(len(x)): # nur da, damit die Funktion auch Zeit verbraucht
        a = i * i
    return sum(x)

def main(num_procs):
    pool = mp.Pool(num_procs)
    result = pool.map(my_func, split(list(range(10**8)), num_procs))

    print("num_procs:", num_procs, "result:", sum(result))

if __name__ == "__main__":
    start_time = time.process_time()
    main(int(sys.argv[1]))
    print(f'time needed: {(time.process_time() - start_time)} s')
Jetzt teste ich das Ganze mit 1,2,4 und 8 Prozessen und bekomme dafür folgende Ausgabe:

Code: Alles auswählen

num_procs: 1 result: 4999999950000000
time needed: 6.375935067 s
num_procs: 2 result: 4999999950000000
time needed: 6.353192033 s
50000000
50000000
num_procs: 4 result: 4999999950000000
time needed: 6.453357544999999 s
25000000
25000000
25000000
25000000
num_procs: 8 result: 4999999950000000
time needed: 6.496723103 s
12500000
12500000
12500000
12500000
12500000
12500000
12500000
12500000
Drei Sachen verstehe ich nicht:
1. Für num_procs = 1 fehlt die Ausgabe von print(len(x)) (erste Aktion in my_func), wieso?
2. Wie kann es sein, dass die Ausgaben von print(len(x)) erst kommen, nachdem das Ergebnis und die Zeit geprintet werden?
3. Was mache ich falsch, dass mehr Prozesse länger brauchen?

Re: Multiprocessing immer gleich langsam

Verfasst: Sonntag 20. Februar 2022, 17:15
von __deets__
Ich habe damit ein bisschen rumgespielt, und so hier bekomme ich die gewuenschten Ergebnisse:

Code: Alles auswählen

import time
import multiprocessing as mp
import sys


def my_func(wait):
    time.sleep(wait)
    return wait


def main(num_procs):
    ranges = [10.0 / num_procs] * num_procs
    pool = mp.Pool(num_procs)
    start_time = time.monotonic()
    result = pool.map(my_func, ranges)
    print(f'time needed: {(time.monotonic() - start_time)} s')

if __name__ == "__main__":
    main(int(sys.argv[1]))
Ich vermute das Original-Problem liegt darin, dass deine Datenmenge, die du transferierst, das Geschehen dominiert. Zumindest ich habe keinen signifikanten Unterschied beim auskommentieren von der for-Schleife gesehen. Und die Datenmenge, die da durch die Gegend geschaufelt wird, durch Pipes oder was auch, ist eben immer gleich - dadurch braucht das auch gleichlang.

Erst wenn du etwas berechnest, das wirklich davon profitiert, eine teure Rechnung weniger lang zu taetigen, wird sich da was tun.

Re: Multiprocessing immer gleich langsam

Verfasst: Sonntag 20. Februar 2022, 17:37
von __blackjack__
@CptK: `process_time()` misst die Zeit von dem Hauptprozess und zwar nicht die „wall time“ sondern nur die Zeit, die dieser Prozess aktiv war. Und das verteilen und sammeln der Aufgabe/Ergebnisse dauert halt immer ungefähr gleich, beziehungsweise steigt sogar leicht wenn die Zahl der Prozesse steigt. Was dort nicht gemessen wird, ist schlafen/warten auf andere Prozesse, denn zu der Zeit ist der Hauptprozess ja nicht aktiv. Der erste Fehler ist also, dass Du falsch misst.

Das zweite Problem dürfte werden/sein, dass `map()` per Default nicht jede Teilaufgabe einzeln an einen Prozess übergibt, sondern die zu ”chunks” zusammenfasst. Wie viele, hängt von der Grösse des Pools ab. Da müsste man also explizit die Anzahl 1 für die ”chunks” an `map()` übergeben, wenn man jede Teilaufgabe einem eigenen Prozess zuordnen möchte.