2012-12-07 21 views
5

Jestem całkiem nowy w programowaniu i stworzyłem program do pobierania danych o inwentarzu z odtwarzaczy Team Fortress 2 i umieszczania elementów w ekwipunku w słowniku z steamidem jako kluczem i listą pozycji jako wartości .Słownik Pythona zjada ram

Problem polega na tym, że po około 6000 wpisach do słownika program całkowicie zasysał całą pamięć RAM w moim systemie i wyłącza się.

Zgaduję, że słownik staje się po prostu zbyt duży, ale według tego, co przeczytałem z podobnych pytań, dykta 6000 wpisów nie powinna zajmować tak dużej części pamięci RAM.

Szukałem innych rozwiązań, ale mógłbym użyć konkretnych przykładów dla mojego kodu.

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") 

ja naprawdę nie wiem o inny sposób to zrobić zachowując słownika appearence, co jest dość ważne, ponieważ chciałbym, aby móc powiedzieć, których asortyment jest. Jeśli byłem niejasny w cokolwiek z tego, po prostu powiedzieć tak i postaram się wyjaśnić

Odpowiedz

4

Myślę, że masz kilka błędów logicznych w swoim kodzie. Na przykład dodajesz przedmioty z ekwipunku każdego gracza do słownika inventory, a następnie iterujesz po nim, aby wypełnić inne rzeczy.

Jednak nigdy nie resetujesz słownika inventory, więc nadal gromadzi przedmioty (dzięki czemu drugi gracz będzie posiadał ekwipunek pierwszej osoby oprócz własnych).

Masz podobny problem ze słownikiem items, którego używasz nieco później. Zresetowałeś go do emptyitems, który był pierwotnie pustą listą, ale ponieważ przypisanie w Pythonie jest przez odniesienie, nie ma to żadnego skutku (items był już tym samym obiektem co emptyitems).

Dzięki tym dwóm poprawkom możesz mieć większą szansę na niewykorzystanie całej pamięci systemu.

Innym Różne poprawa kodu (prawdopodobnie nie związane z użycia pamięci):

W swojej pętli nad inventory, masz dostęp wielokrotnie te same dwie wartości, a nie za pomocą key do niczego. Zamiast for key in inventory spróbuj for value1, value2 in inventory.itervalues() (lub in inventory.values(), jeśli używasz Pythona 3). Następnie użyj value1 zamiast inventory[key][0] i value2 w miejsce inventory[key][1] (lub jeszcze lepiej, nadaj im bardziej znaczące nazwy).

Edit: Oto jak może wyglądać pętla (ja rodzaj zgadywania na nazwy dla dwóch wartości, które wcześniej były w inventory[key][0] i 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

A więc dodanie: inventory = dict() items = list() na początku pętli "for steamid in steamprofiler" powinno uniemożliwić wgranie pamięci do pewien stopień? Nie bardzo rozumiem problem z pętlą inwentaryzacji, kluczowe wartości w ekwipunku odpowiadają imionom w index_to_name i index_to_quality, w jaki sposób twoje rozwiązanie robi to lepiej? Nie mówię tutaj, jestem naprawdę ciekawy, bo jestem całkiem nowy. – Tenbin

+0

Jeśli chodzi o pętlę nad 'inwentarzem', to po prostu było trochę dziwne, że korzystałeś z' inventory [key] [0] 'oraz' inventory [key] [0] 'i nie uzyskując dostępu do' klucza' gdziekolwiek indziej. Jeśli są to wartości, których musisz użyć (do indeksowania w innych słownikach), sugeruję, aby pętla była iterowana bezpośrednio na nich. Jeśli 'inventory [key]' jest dwuelementową krotką lub listą, możesz rozpakować ją do dwóch zmiennych bezpośrednio w instrukcji 'for'. Zmienię moją odpowiedź, aby pokazać, jak to będzie wyglądać, z odpowiednim wcięciem. – Blckknght

1

Uważam ten ilustruje problem z kodem:

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

Innymi słowy, jesteś przechwytywania odniesienie do listy emptyitems, która będzie nadal bardzo rosła. Prawdopodobnie nie to miałeś na myśli i mogę sobie wyobrazić, że bardzo żmudna jest pamięć, aby żonglować bardzo dużą listą.

+0

Chyba ustalone, że przez dodanie elementów = list() do początku dla steamidu w pętli steamprofilera, okrzyki – Tenbin

Powiązane problemy