python - multiprocessing ikke opnå fuld CPU brug på dual-processor windows maskine

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg arbejder på en dual-processor windows maskine og forsøger at køre adskillige uafhængige python processer ved hjælp af multiprocessing biblioteket. Selvfølgelig sigter jeg på at maksimere brugen af ​​begge CPU'er for at fremskynde beregningstiden. Detaljerne på min maskine er nedenfor:



  • OS: Windows 10 Pro til arbejdsstationer

  • RAM: 524 GB

  • Harddisk: Samsung SSD PRO 960 (NVMe)

  • CPU: Xeon Gold 6154 (gange 2)



Jeg udfører et master-script ved hjælp af Python 3.6, som derefter springer 72 hukommelsesafhængige arbejdere ved hjælp af multiprocessing-biblioteket. I begyndelsen anvendes alle 72 kerner i min maskine til 100\%. Efter ca. 5-10 minutter reduceres alle 36 af kernerne på min anden CPU til 0\%, mens de 36 kerner på den første CPU forbliver på 100\%. Jeg kan ikke finde ud af, hvorfor dette sker.


Er der noget, jeg mangler med hensyn til udnyttelsen af ​​begge CPU'er i en dual-processor Windows-maskine? Hvordan kan jeg sikre, at mit maskinens fulde potentiale udnyttes? Som en sidebemærkning er jeg nysgerrig, om det ville være anderledes hvis jeg brugte et Linux-operativsystem? På forhånd tak for alle, der er villige til at hjælpe med dette.


En gengivelse af mit python master script er nedenfor:


import pandas as pd
import netCDF4 as nc
from multiprocessing import Pool

WEATHERDATAPATH = "C:/Users/..../weatherdata/weatherfile\_\%s.nc4"
OUTPUTPATH = "C:/Users/....outputs/result\_\%s.nc4"

def calculationFunction(year):
    dataset = nc.Dataset(WEATHERDATAPATH\%year)

    # Read the data
    data1 = dataset["windspeed"][:]
    data2 = dataset["pressure"][:]
    data3 = dataset["temperature"][:]

    timeindex = nc.num2date(dataset["time"][:], dataset["time"].units)

    # Do computations with the data, primarily relying on NumPy
    data1Mean = data1.mean(axis=1)
    data2Mean = data2.mean(axis=1)
    data3Mean = data3.mean(axis=1)

    # Write result to a file
    result = pd.DataFrame( {"windspeed":data1Mean,
                            "pressure":data2Mean,
                            "temperature":data3Mean,}, 
                          index=timeindex )
    result.to\_csv(OUTPUTPATH\%year)

if \_\_name\_\_ == '\_\_main\_\_':
    pool = Pool(72)

    results = []
    for year in range(1900,2016): 
        results.append( pool.apply\_async(calculationFunction, (year, )))

    for r in results: r.get()

Bedste reference


Det viser sig, at problemet var med NumPy. Som denne løsning forklarer, er NumPy og flere andre lignende pakker afhængige af BLAS-biblioteket til numerisk drift. Dette bibliotek bruger multithreading for at øge ydeevnen. Men som multithreading er CPU-bundet, forårsager dette mange handlinger udført af Numpy (som i min oprindelige kode ikke begynder til midten, som jeg har angivet), at blive tvunget til den første CPU.


Løsningen er at slukke for multithreading-funktionen i BLAS-biblioteket. Jeg er ikke sikker på, om dette påvirker ydeevnen, men i dette tilfælde tror jeg det vil være okay. Heldigvis er det nemt at gøre, jeg havde kun at indstille en enkelt miljøvariabel, som jeg gjorde direkte i min python kode:


import os
os.environ["OPENBLAS\_MAIN\_FREE"] = "1"


Nu kører maskinen med fuld kapacitet i hele min kode :)

Andre referencer 1


Dette kan skyldes Windows kerneparkering.


Overraskende ser det ikke ud til at være en endelig beskrivelse af funktionen på nettet, kun skrot af information.


I princippet er flere kerner/CPU'er involveret, jo højere er synkroniseringsoverhead (det er kvadratisk) og strømforbrug. Så Win7 + forsøger at bruge de færrest kerne/CPU'er, der er tilstrækkelige til den aktuelle arbejdsbyrde. På samme måde har SMP-synkronisering en forskellige overhead sammenlignet med inter-core synkronisering - formodentlig højere 'cuz en CPU skal låse den delte hukommelsesbuss for at gøre sammenkoblede operationer, helt lukke den anden CPU (er), mens kerner har mere spillerum, da der ikke er nogen industristandarder styrer hvad der sker inden for en CPU.


Dine opgaver er delvist CPU-bundet, delvist I/O-bundet. I pc'er er bulk I/O generelt lavet med DMA, hvilket giver CPU mulighed for at skifte til andre ting i mellemtiden. Så teoretisk kan din arbejdsbyrde håndteres af færre kerner end der er arbejdere.





For det første skal du kontrollere, om dette er tilfældet. Det er trods alt måske, at nogle arbejdere har afsluttet og noget, der ikke er tilfældet.


Først og fremmest kan du køre Task Manager efter din belastning og se om nogen af ​​kernerne er markeret 'Parkeret'.


Brug derefter disse fejlfindingstryk i medarbejderfunktionen mellem trin for at finde ud af, hvor den er i gang:


print("PID: \%d, CPU: \%d"\%(os.getpid(),ctypes.windll.kernel32.GetCurrentProcessorNumber())



  • En tråd kan planlægges til en anden CPU hver tidsluke, at den får kontrol (spaltidspunktet er ~ 10 ms i Windows IIRC). Så individuelle tal betyder ikke noget, kun de aggregerede statistikker gør. Win7 + forsøger at planlægge samme tråd til den samme kerne, når det er praktisk for at reducere behovet for cache flushes.



Alternativt kan du redigere trace.py:localtrace\_trace() i standardbiblioteket for at certificere denne info og køre dit program med sporing for at få mere statistik (bemærk at den store mængde sporing vil ændre arbejdsbyrden mod I/O, så pas på, når du fortolker resultaterne).





Nu, hvis det viser sig at være kerneparkering, her er hvordan du styrer det.


MS offentliggør ikke disse oplysninger - sandsynligvis fordi de vil have friheden til at ændre det, eller fordi det er for dybt for de fleste brugere at bruge meningsfuldt.



  • Gå til HKEY\_LOCAL\_MACHINESYSTEMCurrentControlSetControlPowerPowerSettings54533251-82be-4824-96c1-47b60b740d00. I værdier ser du at dette er et registreringsdatabase for processorens strømindstillinger i Appendiks-kontrolpanelets app.

  • Mange af dem har Attributes værdi af 00000001 (den mindst signifikante bit sæt), hvilket betyder at de er skjult fra appens GUI. For at vise dem skal du


    • deaktiver LSB'en i registreringsværdien, eller

    • Kør `powercfg -attributes -ATTRIB\_HIDE, som ville gøre det samme




Da MS ikke forklarer hvilken værdi, hvilket (alt, hvad vi har, er forklarende tekst i disse registernøgler - som også vises i GUI'en, hvis du overholder indstillingerne), er der stor forvirring om deres mening omkring nettet - herunder fra utility writers.


I det mindste vil indstillingen "Processor performance core parking min cores" til 100\% effektivt deaktivere parkering (men ikke inaktiv tilstand og frekvensstyring).


Strøm og ydeevne Tuning | Microsoft Docs siger, at 'High Performace' -profilen for server-Windows-systemer deaktiverer parkering og frekvensregulering helt - så den mest pålidelige måde er at få en af ​​disse operativsystemer og kopiere alle indstillinger fra den pågældende profil. [10]