Większość funkcji Numpy domyślnie włącza wielowątkowość.
na przykład pracuję na 8-rdzeniowej stacji roboczej z procesorem Intel, jeśli uruchomię skrypt
import numpy as np
x=np.random.random(1000000)
for i in range(100000):
np.sqrt(x)
Linux top
wyświetli 800% użycia procesora podczas pracy,
co oznacza, że numpy automatycznie wykrywa, że moja stacja robocza ma 8 rdzeni i np.sqrt
automatycznie używa wszystkich 8 rdzeni, aby przyspieszyć obliczenia.
Znalazłem jednak dziwny błąd. Jeśli uruchomię skrypt
import numpy as np
import pandas as pd
df=pd.DataFrame(np.random.random((10,10)))
df+df
x=np.random.random(1000000)
for i in range(100000):
np.sqrt(x)
użycie procesora wynosi 100% !!. Oznacza to, że jeśli dodasz dwie pandy DataFrame przed uruchomieniem dowolnej funkcji numpy, funkcja automatycznego wielowątkowości numpy zniknie bez żadnego ostrzeżenia! To absolutnie nieuzasadnione, dlaczego obliczenia Pandas dataFrame wpłynęłyby na ustawienie wątków Numpy? Czy to błąd? Jak obejść ten problem?
PS:
Kopie dalej za pomocą perf
narzędzia Linux .
uruchamianie pierwszych pokazów skryptów
Podczas uruchamiania drugiego pokazuje skrypt
Zatem oba skrypty obejmują libmkl_vml_avx2.so
, podczas gdy pierwszy skrypt obejmuje dodatkowe, libiomp5.so
które wydają się być powiązane z openMP.
A ponieważ vml oznacza bibliotekę wektorów matematycznych Intel, więc zgodnie z vml doc myślę, że przynajmniej poniższe funkcje są automatycznie wielowątkowe
import numpy as np import pandas as pd import os os.environ["MKL_NUM_THREADS"] = '4' print(os.environ["MKL_NUM_THREADS"]) df=pd.DataFrame(np.random.random((10,10))) df+df print(os.environ["MKL_NUM_THREADS"]) a = np.random.random((20000000, 3)) b = np.random.random((3, 30)) for _ in range(10): c = np.dot(a, b)
Odpowiedzi:
Panda używa
numexpr
pod maską do obliczania niektórych operacji inumexpr
ustawia maksymalną liczbę wątków dla vml na 1, gdy jest importowany :i jest importowany przez pandy, gdy
df+df
jest oceniany w expressions.py :Jednak dystrybucja Anaconda wykorzystuje również VML-funkcjonalność takich funkcji jak
sqrt
,sin
,cos
i tak dalej - i raznumexpr
ustawić maksymalna liczba wątków do VML-1, NumPy-funkcjonuje już używać zrównoleglanie.Problem można łatwo zauważyć w gdb (używając powolnego skryptu):
tzn. widzimy,
numexpr
ustawia liczbę wątków na 1. Co jest później używane, gdy wywoływana jest funkcja vml-sqrt:Widzimy więc, że numpy używa implementacji vml, z
vdSqrt
której korzysta,mkl_vml_serv_threader_d_1i_1o
aby zdecydować, czy obliczenia powinny być wykonywane równolegle i wygląda na liczbę wątków:rejestr
%rax
ma maksymalną liczbę wątków i wynosi 1.Teraz możemy użyć
numexpr
do zwiększenia liczby wątków vml , tj .:Teraz wykorzystuje się wiele rdzeni!
źródło
numexpr
za kulisami.Patrząc na numpy, wygląda na to, że pod maską miał problemy z włączaniem / wyłączaniem wielowątkowości, i w zależności od używanej wersji, możesz spodziewać się awarii, gdy podbijesz ne.set_vml_num_threads () ..
http://numpy-discussion.10968.n7.nabble.com/ANN-NumExpr-2-7-0-Release-td47414.html
Muszę się zastanowić, jak to jest przyklejone do interpretera python, biorąc pod uwagę twój przykład kodu, w którym wydaje się, że w jakiś sposób pozwala na wiele pozornie synchronicznych / uporządkowanych wywołań do np.sqrt () równolegle. Wydaje mi się, że jeśli interpreter Pythona zawsze zwraca referencję do obiektu, gdy wyskakuje on na stosie, a w twoim przykładzie jest po prostu przechwytywanie tych referencji, a nie przypisywanie lub manipulowanie nimi w jakikolwiek sposób, byłoby dobrze. Ale jeśli kolejne iteracje pętli zależą od poprzednich, wydaje się mniej jasne, jak można je bezpiecznie zrównoleglić. Prawdopodobnie cicha awaria / błędne wyniki są gorsze niż awarie.
źródło
Myślę, że twoje początkowe założenie może być nieprawidłowe -
Stwierdziłeś: co oznacza, że numpy automatycznie wykrywa, że moja stacja robocza ma 8 rdzeni, a np.sqrt automatycznie używa wszystkich 8 rdzeni w celu przyspieszenia obliczeń.
Pojedyncza funkcja np.sqrt () nie może odgadnąć, w jaki sposób zostanie ona później wywołana lub zwrócona, zanim zostanie częściowo zakończona. W Pythonie istnieją mechanizmy równoległości, ale żaden nie jest automatyczny.
Teraz, powiedziawszy to, interpreter pythona może być w stanie zoptymalizować pętlę for pod kątem równoległości, co może być tym, co widzisz, ale mocno podejrzewam, że jeśli spojrzysz na czas zegara na wykonanie tej pętli, nie będzie różni się niezależnie od tego, czy (najwyraźniej) używasz 8 rdzeni czy 1 rdzeń.
AKTUALIZACJA: Po przeczytaniu nieco więcej komentarzy wydaje się, że obserwowane zachowanie wielordzeniowe jest związane z rozkładem anakondy interpretera python. Przyjrzałem się, ale nie byłem w stanie znaleźć dla niego żadnego kodu źródłowego, ale wygląda na to, że licencja python pozwala podmiotom (takim jak anaconda.com) na kompilowanie i dystrybucję pochodnych interpretera bez konieczności publikowania ich zmian.
Wydaje mi się, że możesz dotrzeć do ludzi anakondy - zachowanie, które widzisz, będzie trudne do zrozumienia, nie wiedząc, co / jeśli coś zmienili w tłumaczu.
Wykonaj również szybką kontrolę czasu zegara ściennego z / bez optymalizacji, aby sprawdzić, czy rzeczywiście jest on 8-krotnie szybszy - nawet jeśli naprawdę masz wszystkie 8 rdzeni zamiast 1, dobrze byłoby wiedzieć, czy wyniki są rzeczywiście 8-krotnie szybciej lub jeśli w użyciu są blokady, które wciąż serializują się na jednym muteksie.
źródło