2012-12-07 41 views
5

Tôi khá mới lập trình và tạo chương trình lấy dữ liệu khoảng không quảng cáo từ người chơi Team Fortress 2 và đặt các mục khoảng không quảng cáo vào từ điển với steamid làm khóa và danh sách các mục làm giá trị .Từ điển Python ăn ram

Sự cố mà tôi đang gặp phải là sau khoảng 6000 mục nhập vào từ điển, chương trình đã hút về cơ bản tất cả RAM trên hệ thống của tôi và tắt.

Tôi đoán từ điển đơn giản trở nên quá lớn nhưng theo những gì tôi đã đọc từ các câu hỏi tương tự, một mệnh đề 6000 mục không nên chiếm nhiều bộ nhớ RAM của tôi.

Tôi đã xem xét các giải pháp khác nhưng tôi có thể sử dụng một số ví dụ cụ thể cho mã của mình.

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

Tôi thực sự không biết cách nào khác để làm điều đó trong khi vẫn giữ lại xuất hiện từ điển, điều này khá quan trọng vì tôi muốn có thể biết được khoảng không quảng cáo của nó là gì. Nếu tôi đã không rõ ràng trong bất kỳ này, chỉ cần nói như vậy và tôi sẽ cố gắng giải thích

Trả lời

4

Tôi nghĩ rằng bạn có một số lỗi logic trong mã của mình. Ví dụ: bạn đang thêm các mục khoảng không quảng cáo của mỗi người chơi vào từ điển inventory, sau đó lặp lại nó để điền vào các nội dung khác.

Tuy nhiên, bạn không bao giờ đặt lại từ điển inventory, do đó, nó tiếp tục tích lũy các mục (vì vậy người thứ hai sẽ xuất hiện để có khoảng không quảng cáo của người đầu tiên ngoài của riêng mình).

Bạn gặp sự cố tương tự với từ điển items mà bạn đang sử dụng sau này. Bạn đặt lại nó thành emptyitems vốn ban đầu là một danh sách trống, nhưng do gán trong Python là tham chiếu, điều này không có hiệu lực (items đã là đối tượng giống như emptyitems).

Với hai bản sửa lỗi đó, bạn có thể có cơ hội tốt hơn khi không sử dụng tất cả bộ nhớ của hệ thống.

Một cải tiến đang linh tinh (có thể không liên quan đến việc sử dụng bộ nhớ):

Trong vòng lặp của bạn trên inventory, bạn đang liên tục truy cập vào hai giá trị giống nhau và không sử dụng key cho bất cứ điều gì. Thay vì for key in inventory hãy thử for value1, value2 in inventory.itervalues() (hoặc in inventory.values() nếu bạn đang sử dụng Python 3). Sau đó, hãy sử dụng value1 thay cho inventory[key][0]value2 thay cho inventory[key][1] (hoặc thậm chí tốt hơn, cung cấp cho họ tên có ý nghĩa hơn).

Sửa: Đây là cách các vòng lặp có thể trông (tôi loại đoán tại tên cho hai giá trị mà trước đây trong inventory[key][0]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

Vì vậy, thêm: inventory = dict() items = list() vào đầu của "steamid in steamprofiler" loop nên ngăn chặn bộ nhớ hogging một mức độ nào đó? Tôi không hoàn toàn hiểu vấn đề với vòng lặp tồn kho, các giá trị chính trong khoảng không quảng cáo tương ứng với tên trong index_to_name và index_to_quality, giải pháp của bạn làm tốt hơn như thế nào? Tôi không cho miệng ở đây, tôi thực sự tò mò vì tôi khá mới. – Tenbin

+0

Về vòng lặp trên 'khoảng không quảng cáo', tôi chỉ có một chút lạ khi bạn truy cập vào' khoảng không quảng cáo [khóa] [0] 'và' khoảng không quảng cáo [khóa] [0] 'và không truy cập vào 'khóa' ở bất kỳ nơi nào khác. Nếu đó là những giá trị bạn cần sử dụng (để lập chỉ mục vào các từ điển khác của bạn), tôi khuyên bạn nên lặp lại vòng lặp trực tiếp trên chúng. Nếu 'inventory [key]' là một tuple hoặc danh sách hai phần tử, bạn có thể giải nén nó thành hai biến ngay trong câu lệnh 'for'. Tôi sẽ chỉnh sửa câu trả lời của mình để hiển thị nó trông như thế nào, với sự thụt đầu thích hợp. – Blckknght

1

Tôi tin rằng đây minh họa một vấn đề với mã của bạn:

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

Nói cách khác, bạn đang chụp một tham chiếu đến danh sách emptyitems, điều này sẽ tiếp tục phát triển rất lớn. Điều này có lẽ không phải là những gì bạn có nghĩa là, và tôi có thể tưởng tượng nó trở nên khá bộ nhớ dữ dội để sắp xếp một danh sách rất lớn.

+0

nghĩ tôi cố định bằng cách thêm các mặt hàng = list() vào đầu của steamid trong vòng lặp steamprofiler, hãy cổ vũ – Tenbin