2012-12-07 9 views
5

Sono abbastanza nuovo alla programmazione e ho creato un programma per recuperare i dati di inventario dai giocatori di Team Fortress 2 e mettere gli oggetti di inventario in un dizionario con steamid come chiave e l'elenco di elementi come valore .Python dictionary eat up ram

Il problema che sto incontrando è che dopo circa 6000 voci nel dizionario il programma ha risucchiato essenzialmente tutta la RAM sul mio sistema e si spegne.

Immagino che il dizionario diventi troppo grande ma da quello che ho letto da domande simili un dittico di 6000 voci non dovrebbe occupare gran parte della mia RAM.

Ho esaminato altre soluzioni, ma potrei utilizzare alcuni esempi concreti per il mio codice.

import re, urllib.request, urllib.error, gzip, io, json, socket, sys 

with open("index_to_name.json", "r", encoding=("utf-8")) as fp: 
    index_to_name=json.load(fp) 

with open("index_to_quality.json", "r", encoding=("utf-8")) as fp: 
    index_to_quality=json.load(fp) 

with open("index_to_name_no_the.json", "r", encoding=("utf-8")) as fp: 
    index_to_name_no_the=json.load(fp) 

with open("steamprofiler.json", "r", encoding=("utf-8")) as fp: 
    steamprofiler=json.load(fp) 

inventory=dict() 
playerinventories=dict() 
c=0 

for steamid in steamprofiler: 
    emptyitems=[] 
    items=emptyitems 
    try: 
     url=urllib.request.urlopen("http://api.steampowered.com/IEconItems_440/GetPlayerItems/v0001/?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&steamid="+steamid+"&format=json") 
     inv=json.loads(url.read().decode("utf-8")) 
     url.close() 
    except (urllib.error.HTTPError, urllib.error.URLError, socket.error) as e: 
     c+=1 
     print("URL/HTTP error, continuing") 
     continue 
    try: 
     for r in inv["result"]["items"]: 
      inventory[r["id"]]=r["quality"], r["defindex"] 
    except KeyError: 
     c+=1 
     print(steamid, "didn't have an inventory") 
     continue 
    for key in inventory: 
     try: 
      if index_to_quality[str(inventory[key][0])]=="": 
       items.append(
        index_to_quality[str(inventory[key][0])] 
        +""+ 
        index_to_name[str(inventory[key][1])] 
        ) 
      else: 
       items.append(
        index_to_quality[str(inventory[key][0])] 
        +" "+ 
        index_to_name_no_the[str(inventory[key][1])] 
        ) 
     except KeyError: 
      print("Key error, uppdate def_to_index") 
      c+=1 
      continue 
playerinventories[int(steamid)]=items 
items=emptyitems 
c+=1 
print(c, "inventories fetched") 

io non so davvero di qualsiasi altro modo per farlo, pur mantenendo la comparsa dizionario, che è abbastanza importante in quanto mi piacerebbe essere in grado di dire di chi l'inventario che è. Se sono stato poco chiaro in tutto questo, basta dirlo e cercherò di spiegare

risposta

4

Penso che tu abbia degli errori logici nel tuo codice. Ad esempio, aggiungi gli articoli di inventario di ciascun giocatore al dizionario inventory, quindi esegui il iter su di esso per riempire altre cose.

Tuttavia, non si sta mai reimpostando il dizionario inventory, quindi continua ad accumulare elementi (in modo che il secondo lettore abbia l'inventario della prima in aggiunta al proprio).

Hai un problema simile con il dizionario items che stai usando un po 'più tardi. L'hai resettato su emptyitems che originariamente era una lista vuota, ma poiché l'assegnazione in Python è per riferimento, ciò non ha alcun effetto (items era già lo stesso oggetto di emptyitems).

Con queste due correzioni si potrebbe avere una migliore possibilità di non utilizzare tutta la memoria del sistema.

Un altro miglioramento del codice Varie (probabilmente non relative a l'utilizzo di memoria):

Nel vostro ciclo su inventory, sei volte l'accesso alle stesse due valori e che non utilizzano il key per qualsiasi cosa. Invece di for key in inventory prova for value1, value2 in inventory.itervalues() (o in inventory.values() se stai usando Python 3). Quindi utilizzare value1 al posto di inventory[key][0] e value2 al posto di inventory[key][1] (o anche meglio, assegnare loro nomi più significativi).

Edit: Ecco come il ciclo potrebbe apparire (sto sorta di indovinare i nomi per i due valori che in precedenza erano in inventory[key][0] e inventory[key][1]):

for quality, name in inventory.itervalues(): 
    try: 
     if index_to_quality[str(quality)]=="": 
      items.append(
       index_to_quality[str(quality)] 
       +""+ 
       index_to_name[str(name)] 
       ) 
     else: 
      items.append(
       index_to_quality[str(quality)] 
       +" "+ 
       index_to_name_no_the[str(name)] 
       ) 
+0

Aggiungendo così: inventory = dict() items = list() all'inizio del ciclo "for steamid in steamprofiler" dovrebbe impedire l'hogging della memoria a qualche grado? Non capisco perfettamente il problema con il ciclo di inventario, i valori chiave nell'inventario corrispondono ai nomi in index_to_name e index_to_quality, come fa la soluzione a fare meglio? Non sto dando la bocca qui, sono sinceramente curioso dato che sono abbastanza nuovo. – Tenbin

+0

Per quanto riguarda il ciclo su "inventario", ho pensato che fosse un po 'strano che tu stessi accedendo a "inventario [chiave] [0]" e "inventario [chiave] [0]" e non accedendo a "chiave" da nessun'altra parte. Se questi sono i valori che devi usare (per l'indicizzazione nei tuoi altri dizionari), ti suggerisco di fare direttamente il ciclo iterato su di essi. Se 'inventory [key]' è una tupla o lista di due elementi, puoi scompattarla in due variabili direttamente nell'istruzione 'for'. Modificherò la mia risposta per mostrare come sarebbe, con indentazione corretta. – Blckknght

1

Credo che questo illustra un problema con il tuo codice:

>>> emptyitems=[] 
>>> a=emptyitems 
>>> a.append("hello") 
>>> a.append("bar") 
>>> a 
['hello', 'bar'] 
>>> emptyitems 
['hello', 'bar'] 

In altre parole, si sta catturando un riferimento all'elenco emptyitems, che continuerà a crescere davvero molto. Questo probabilmente non è quello che volevi dire, e posso immaginare che diventi abbastanza intenso nella memoria per destreggiarsi in una lista molto ampia.

+0

pensi che io fisso che con l'aggiunta di elementi = lista() all'inizio del per steamid nel ciclo steamprofiler, evviva – Tenbin