Rozważmy następującą funkcję:Wieloprocesorowość w języku Python - Dlaczego użycie functools.partial jest wolniejsze od domyślnych?
def f(x, dummy=list(range(10000000))):
return x
Jeśli używam multiprocessing.Pool.imap
, otrzymuję następujące czasy:
import time
import os
from multiprocessing import Pool
def f(x, dummy=list(range(10000000))):
return x
start = time.time()
pool = Pool(2)
for x in pool.imap(f, range(10)):
print("parent process, x=%s, elapsed=%s" % (x, int(time.time() - start)))
parent process, x=0, elapsed=0
parent process, x=1, elapsed=0
parent process, x=2, elapsed=0
parent process, x=3, elapsed=0
parent process, x=4, elapsed=0
parent process, x=5, elapsed=0
parent process, x=6, elapsed=0
parent process, x=7, elapsed=0
parent process, x=8, elapsed=0
parent process, x=9, elapsed=0
Teraz, jeśli mogę użyć functools.partial
zamiast używać wartości domyślnej:
import time
import os
from multiprocessing import Pool
from functools import partial
def f(x, dummy):
return x
start = time.time()
g = partial(f, dummy=list(range(10000000)))
pool = Pool(2)
for x in pool.imap(g, range(10)):
print("parent process, x=%s, elapsed=%s" % (x, int(time.time() - start)))
parent process, x=0, elapsed=1
parent process, x=1, elapsed=2
parent process, x=2, elapsed=5
parent process, x=3, elapsed=7
parent process, x=4, elapsed=8
parent process, x=5, elapsed=9
parent process, x=6, elapsed=10
parent process, x=7, elapsed=10
parent process, x=8, elapsed=11
parent process, x=9, elapsed=11
Dlaczego wersja używająca functools.partial
jest wolniejsza?
Dlaczego używasz 'list (range (...))'? AFAIK twój kod zrobiłby dokładnie to samo bez wezwania do "listy", z wyjątkiem tego, że problem wyjaśniony przez ShadowRanger nie wystąpiłby, a narzut piklowania byłby * znacznie * mniejszy. – Bakuriu
Notatka: Używanie 'list's (lub dowolnego innego typu zmiennego) jako argumentu domyślnego (lub" częściowego "związanego) jest niebezpieczne, ponieważ lista _same_' jest dzielona pomiędzy wszystkimi domyślnymi wywołaniami funkcji, a nie świeżą kopią dla każdego połączenia; zazwyczaj chcesz mieć świeżą kopię. – ShadowRanger
jak na marginesie, jest zwykle zły pomysł używając zmiennego obiektu jako wartości domyślnych, ponieważ jeśli zmodyfikujesz go w funkcji, każde kolejne wywołanie funkcji będzie widoczne zmiany – Copperfield