2017-02-22 11 views
0

Ich arbeite an Code, der mehrere netcdf-Dateien (große ~ 28G) überschleift. Die netcdf-Dateien haben mehrere 4D-Variablen [Zeit, Ost-West, Süd-Nord, Höhe] in einer Domäne. Das Ziel besteht darin, diese Dateien zu durchlaufen und jede Position dieser Variablen in der Domäne zu durchlaufen und bestimmte Variablen zu ziehen, um sie in einem großen Array zu speichern. Wenn fehlende oder unvollständige Dateien vorhanden sind, fülle ich die Werte mit 99.99. Momentan teste ich nur, indem ich täglich zwei netcdf-Dateien durchlaufe, aber aus irgendeinem Grund dauert es ewig (~ 14 Stunden). Ich bin mir nicht sicher, ob es eine Möglichkeit gibt, diesen Code zu optimieren. Ich denke nicht, dass Python für diese Aufgabe so lange braucht, aber vielleicht ist es ein Problem mit Python oder meinem Code. Unten ist mein Code hoffentlich ist es lesbar und Vorschläge, wie diese schneller zu machen ist sehr zu schätzen:Wie kann ich meinen Python-Code schneller laufen lassen?

#Domain to loop over 
k_space = np.arange(0,37) 
j_space = np.arange(80,170) 
i_space = np.arange(200,307) 

predictors_wrf=[] 
names_wrf=[] 

counter = 0 
cdate = start_date 
while cdate <= end_date: 
    if cdate.month not in month_keep: 
     cdate+=inc 
     continue 
    yy = cdate.strftime('%Y')   
    mm = cdate.strftime('%m') 
    dd = cdate.strftime('%d') 
    filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
    for i in i_space: 
     for j in j_space: 
      for k in k_space: 
        if os.path.isfile(filename): 
         f = nc.Dataset(filename,'r') 
         times = f.variables['Times'][1:] 
         num_lines = times.shape[0] 
         if num_lines == 144: 
          u = f.variables['U'][1:,k,j,i] 
          v = f.variables['V'][1:,k,j,i] 
          wspd = np.sqrt(u**2.+v**2.) 
          w = f.variables['W'][1:,k,j,i] 
          p = f.variables['P'][1:,k,j,i] 
          t = f.variables['T'][1:,k,j,i] 
         if num_lines < 144: 
          print "partial files for WRF: "+ filename 
          u = np.ones((144,))*99.99 
          v = np.ones((144,))*99.99 
          wspd = np.ones((144,))*99.99 
          w = np.ones((144,))*99.99 
          p = np.ones((144,))*99.99 
          t = np.ones((144,))*99.99 
        else: 
         u = np.ones((144,))*99.99 
         v = np.ones((144,))*99.99 
         wspd = np.ones((144,))*99.99 
         w = np.ones((144,))*99.99 
         p = np.ones((144,))*99.99 
         t = np.ones((144,))*99.99 
         counter=counter+1 
        predictors_wrf.append(u) 
        predictors_wrf.append(v) 
        predictors_wrf.append(wspd) 
        predictors_wrf.append(w) 
        predictors_wrf.append(p) 
        predictors_wrf.append(t) 
        u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i) 
        v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i) 
        wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i) 
        w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i) 
        p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i) 
        t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i) 
        names_wrf.append(u_names) 
        names_wrf.append(v_names) 
        names_wrf.append(wspd_names) 
        names_wrf.append(w_names) 
        names_wrf.append(p_names) 
        names_wrf.append(t_names) 
    cdate+=inc 
+0

Sie können Multiprocessing verwenden, um die Dateien gleichzeitig zu verarbeiten. ordnen Sie die k, j, i Leerzeichen für verschiedene Prozesse an und lassen Sie jede von ihnen ihre eigene Aufgabe ausführen – haifzhan

+0

Was ist 'nc.Dataset'? Bevor Sie * Geschwindigkeit * verbessern können, müssen Sie außerdem wissen, warum es langsam ist. Sie müssen Ihren Code profilieren und * messen *. –

+0

es ist, wie ich in netcdf-Dateien mit Python lese ich habe eine Aussage früher im Code, der hier nicht gezeigt wird: netCDF4 als nc – HM14

Antwort

1

Dies ist ein lahmer erster Durchgang, um Ihre forloop s zu verschärfen. Da Sie die Dateiform nur einmal pro Datei verwenden, können Sie die Verarbeitung außerhalb der Schleife verschieben, wodurch sich die Datenmenge beim Unterbrechen der Verarbeitung verringern könnte. Ich bekomme immer noch nicht, was counter und inc tun, da sie nicht in der Schleife aktualisiert werden. Sie wollen auf jeden Fall in wiederholten String-Verkettung Performance aussehen, oder wie die Leistung Ihrer Anfügen zu predictors_wrf und names_wrf sieht aus, als Ausgangspunkte

k_space = np.arange(0,37) 
j_space = np.arange(80,170) 
i_space = np.arange(200,307) 

predictors_wrf=[] 
names_wrf=[] 

counter = 0 
cdate = start_date 
while cdate <= end_date: 
    if cdate.month not in month_keep: 
     cdate+=inc 
     continue 
    yy = cdate.strftime('%Y')   
    mm = cdate.strftime('%m') 
    dd = cdate.strftime('%d') 
    filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
    file_exists = os.path.isfile(filename) 
    if file_exists: 
     f = nc.Dataset(filename,'r') 
     times = f.variables['Times'][1:] 
     num_lines = times.shape[0] 
    for i in i_space: 
     for j in j_space: 
      for k in k_space: 
        if file_exists:  
         if num_lines == 144: 
          u = f.variables['U'][1:,k,j,i] 
          v = f.variables['V'][1:,k,j,i] 
          wspd = np.sqrt(u**2.+v**2.) 
          w = f.variables['W'][1:,k,j,i] 
          p = f.variables['P'][1:,k,j,i] 
          t = f.variables['T'][1:,k,j,i] 
         if num_lines < 144: 
          print "partial files for WRF: "+ filename 
          u = np.ones((144,))*99.99 
          v = np.ones((144,))*99.99 
          wspd = np.ones((144,))*99.99 
          w = np.ones((144,))*99.99 
          p = np.ones((144,))*99.99 
          t = np.ones((144,))*99.99 
        else: 
         u = np.ones((144,))*99.99 
         v = np.ones((144,))*99.99 
         wspd = np.ones((144,))*99.99 
         w = np.ones((144,))*99.99 
         p = np.ones((144,))*99.99 
         t = np.ones((144,))*99.99 
         counter=counter+1 
        predictors_wrf.append(u) 
        predictors_wrf.append(v) 
        predictors_wrf.append(wspd) 
        predictors_wrf.append(w) 
        predictors_wrf.append(p) 
        predictors_wrf.append(t) 
        u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i) 
        v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i) 
        wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i) 
        w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i) 
        p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i) 
        t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i) 
        names_wrf.append(u_names) 
        names_wrf.append(v_names) 
        names_wrf.append(wspd_names) 
        names_wrf.append(w_names) 
        names_wrf.append(p_names) 
        names_wrf.append(t_names) 
    cdate+=inc 
1

Ich habe nicht sehr viele Vorschläge haben, aber ein paar Dinge zu beachten.

Öffnen Sie diese Datei nicht so oft

Zunächst definieren Sie diese filename Variable und dann innerhalb dieser Schleife (tief im Inneren: drei for-Schleifen tief), Sie überprüfen, ob die Datei vorhanden ist und vermutlich dort öffnen es (ich weiß nicht, was nc.Dataset tut, aber ich vermute, es muss die Datei öffnen und lesen):

filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
    for i in i_space: 
     for j in j_space: 
      for k in k_space: 
        if os.path.isfile(filename): 
         f = nc.Dataset(filename,'r') 

das ist ziemlich ineffizient sein würde. Sie können es sicher einmal öffnen, wenn sich die Datei vor all Ihren Loops nicht ändert.

Try to Use Weniger

dieser for-Schleifen Alle verschachtelten for-Schleifen sind die Anzahl der Operationen Compoundierung Sie ausführen müssen. Allgemeiner Vorschlag: Versuchen Sie stattdessen, numpy Operationen zu verwenden.

Verwenden Cprofile

Wenn Sie wollen wissen, warum Ihre Programme sind eine lange Zeit, eine der besten Möglichkeiten, um herauszufinden, ist es, sich zu profilieren.

2

Für Ihre Fragen, ich glaube multiprocessing viel helfen. Ich habe Ihre Codes durchgesehen und habe einige Ratschläge hier.

  1. Nicht Startzeit, aber die Dateinamen als die Iteratoren in Ihren Codes.

    Wickeln Sie eine Funktion, um alle Dateinamen anhand der Uhrzeit zu ermitteln und eine Liste aller Dateinamen zurückzugeben.

    def fileNames(start_date, end_date): 
        # Find all filenames. 
        cdate = start_date 
        fileNameList = [] 
        while cdate <= end_date: 
         if cdate.month not in month_keep: 
          cdate+=inc 
          continue 
         yy = cdate.strftime('%Y')   
         mm = cdate.strftime('%m') 
         dd = cdate.strftime('%d') 
         filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
         fileNameList.append(filename) 
         cdate+=inc 
    
        return fileNameList 
    
  2. Wickeln Sie Ihre Codes, die Ihre Daten ziehen und mit 99 füllen.99 ist die Eingabe für die Funktion der Dateiname.

    def dataExtraction(filename): 
        file_exists = os.path.isfile(filename) 
        if file_exists: 
         f = nc.Dataset(filename,'r') 
         times = f.variables['Times'][1:] 
         num_lines = times.shape[0] 
        for i in i_space: 
         for j in j_space: 
          for k in k_space: 
           if file_exists:  
            if num_lines == 144: 
             u = f.variables['U'][1:,k,j,i] 
             v = f.variables['V'][1:,k,j,i] 
             wspd = np.sqrt(u**2.+v**2.) 
             w = f.variables['W'][1:,k,j,i] 
             p = f.variables['P'][1:,k,j,i] 
             t = f.variables['T'][1:,k,j,i] 
            if num_lines < 144: 
             print "partial files for WRF: "+ filename 
             u = np.ones((144,))*99.99 
             v = np.ones((144,))*99.99 
             wspd = np.ones((144,))*99.99 
             w = np.ones((144,))*99.99 
             p = np.ones((144,))*99.99 
             t = np.ones((144,))*99.99 
            else: 
             u = np.ones((144,))*99.99 
             v = np.ones((144,))*99.99 
             wspd = np.ones((144,))*99.99 
             w = np.ones((144,))*99.99 
             p = np.ones((144,))*99.99 
             t = np.ones((144,))*99.99 
             counter=counter+1 
            predictors_wrf.append(u) 
            predictors_wrf.append(v) 
            predictors_wrf.append(wspd) 
            predictors_wrf.append(w) 
            predictors_wrf.append(p) 
            predictors_wrf.append(t) 
            u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i) 
            v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i) 
            wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i) 
            w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i) 
            p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i) 
            t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i) 
            names_wrf.append(u_names) 
            names_wrf.append(v_names) 
            names_wrf.append(wspd_names) 
            names_wrf.append(w_names) 
            names_wrf.append(p_names) 
            names_wrf.append(t_names) 
    
    
        return zip(predictors_wrf, names_wrf) 
    
  3. Verwenden Sie Multiprocessing, um Ihre Arbeit zu erledigen. Im Allgemeinen haben alle Computer mehr als 1 CPU-Kerne. Multiprocessing erhöht die Geschwindigkeit bei massiven CPU-Berechnungen. Nach meiner bisherigen Erfahrung wird Multiprocessing die Zeit für große Datenmengen um bis zu zwei Drittel reduzieren.

    Updates: Nach dem Testen meiner Codes ein Dateien wieder am 25. Februar 2017, fand ich, dass die Verwendung von 8 Kernen für einen riesigen Datensatz mich 90% der zusammengefallenen Zeit gespeichert.

    if __name__ == '__main__': 
         from multiprocessing import Pool # This should be in the beginning statements. 
         start_date = '01-01-2017' 
         end_date = '01-15-2017' 
         fileNames = fileNames(start_date, end_date) 
         p = Pool(4) # the cores numbers you want to use. 
         results = p.map(dataExtraction, fileNames) 
         p.close() 
         p.join() 
    
  4. schließlich über die Datenstrukturen hier vorsichtig sein, da es ziemlich kompliziert ist. Hoffe das hilft. Bitte hinterlassen Sie Kommentare, wenn Sie weitere Fragen haben.

Verwandte Themen