0

Steam API からインベントリ データを取得するスクリプトを作成しましたが、速度に少し不満があります。だから私はPythonでのマルチプロセッシングについて少し読んだだけで、頭を包み込むことができません。このプログラムは次のように動作します。リストから SteamID を取得し、インベントリを取得してから、ID をキー、インベントリの内容を値として、SteamID とインベントリをディクショナリに追加します。

また、マルチプロセッシング時にカウンターを使用することに関連するいくつかの問題があることも理解しました。これは、最初からではなく、最後に取得したインベントリからプログラムを再開できるようにしたいため、小さな問題です。

とにかく、私が求めているのは、インベントリ データを含む URL を開くときにマルチプロセッシングを実行して、プログラムが一度に 1 つではなく複数のインベントリを取得できるようにする方法の具体的な例です。

コードに:

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)

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

error=list()
playerinventories=dict()
c=127480

while c<len(steamprofiler):
    inventory=dict()
    items=list()
    try:
        url=urllib.request.urlopen("http://api.steampowered.com/IEconItems_440/GetPlayerItems/v0001/?key=DD5180808208B830FCA60D0BDFD27E27&steamid="+steamprofiler[c]+"&format=json")
        inv=json.loads(url.read().decode("utf-8"))
        url.close()
    except (urllib.error.HTTPError, urllib.error.URLError, socket.error, UnicodeDecodeError) as e:
        c+=1
        print("HTTP-error, continuing")
        error.append(c)
        continue
    try:
        for r in inv["result"]["items"]:
            inventory[r["id"]]=r["quality"], r["defindex"]
    except KeyError:
        c+=1
        error.append(c)
        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("keyerror, uppdate def_to_index")
            c+=1
            error.append(c)
            continue
    playerinventories[int(steamprofiler[c])]=items
    c+=1
    if c % 10==0:
        print(c, "inventories downloaded")

私の問題が明確であることを願っています。それ以外の場合は、明らかにそう言ってください。サードパーティのライブラリの使用を最適に回避しますが、それが不可能な場合は不可能です。前もって感謝します

4

2 に答える 2

1

では、URL のフェッチがプログラムの速度を低下させている可能性があると想定していますか? 最初にその仮定を確認することをお勧めしますが、実際にそうである場合、multiprocessingモジュールを使用するのは非常にやり過ぎです: I/O バウンドのボトルネックの場合、スレッド化はかなり単純であり、少し高速でさえある可能性があります (もっと多くの時間がかかります)。スレッドを生成するよりも、別の Python インタープリターを生成する時間)。

コードを見ると、 while ループの内容のほとんどをcパラメーターとして関数に貼り付けて、そこから別の関数を使用してスレッドを開始することができます。たとえば、次のようになります。

def process_item(c):
    # The work goes here
    # Replace al those 'continue' statements with 'return'

for c in range(127480, len(steamprofiler)):
    thread = threading.Thread(name="inventory {0}".format(c), target=process_item, args=[c])
    thread.start()

本当の問題は、生成されるスレッドの量に制限がなく、プログラムが壊れる可能性があることです。また、Steam の担当者は、あなたのスクリプトによって攻撃されることに面白がらず、あなたとのフレンドを解除することを決定する可能性があります。

より良いアプローチは、collections.dequeオブジェクトに のリストを入力してcから、限られた一連のスレッドを開始して作業を行うことです。

def process_item(c):
    # The work goes here
    # Replace al those 'continue' statements with 'return'

def process():
    while True:
       process_item(work.popleft())

work = collections.deque(range(127480, len(steamprofiler)))

threads = [threading.Thread(name="worker {0}".format(n), target=process)
                   for n in range(6)]
for worker in threads:
    worker.start()

work.popleft()仕事がないときにをスローすることを期待していることに注意してくださいIndexError。これにより、スレッドが強制終了されます。これは少し卑劣なので、try...except代わりに a を使用することを検討してください。

さらに2つのこと:

  1. 代わりに優れたRequestsライブラリを使用することを検討してくださいurllib(これは、API に関しては、私が使用した Python 標準ライブラリ全体の中で断然最悪のモジュールです)。
  2. リクエストには、完全に非同期の HTTP リクエストを実行できるgrequestsというアドオンがあります。これにより、さらに単純なコードが作成されます。

これがお役に立てば幸いですが、これはすべてテストされていないコードであることを覚えておいてください。

于 2012-12-11T20:48:42.593 に答える
0

最も外側の while ループは、いくつかのプロセス (またはタスク) に分散しているようです。

ループをタスクに分割するときは、プロセス間で共有playerinventoriesし、反対していることに注意してください。共有の問題errorに使用する必要があります。multiprocessing.Manager

このスニペットからコードの変更を開始することをお勧めします。

于 2012-12-10T15:11:12.180 に答える