4

私は、(少なくとも今は) TwitchTV (ストリーミング プラットフォーム) からストリーム情報を取得するプログラムを作成しています。このプログラムは自己啓発用ですが、実行すると、ストリーマーの名前だけを出力するのに 2 分かかります。

とにかく重要な場合は、Windows7でPython 2.7.3 64ビットを使用しています。

クラス.py:

#imports:
import urllib
import re

#classes:
class Streamer:

    #constructor:
    def __init__(self, name, mode, link):
        self.name = name
        self.mode = mode
        self.link = link

class Information:

    #constructor:
    def __init__(self, TWITCH_STREAMS, GAME, STREAMER_INFO):
        self.TWITCH_STREAMS = TWITCH_STREAMS
        self.GAME = GAME
        self.STREAMER_INFO = STREAMER_INFO

    def get_game_streamer_names(self):
        "Connects to Twitch.TV API, extracts and returns all streams for a spesific game."

        #start connection
        self.con = urllib2.urlopen(self.TWITCH_STREAMS + self.GAME)
        self.info = self.con.read()
        self.con.close()

        #regular expressions to get all the stream names
        self.info = re.sub(r'"teams":\[\{.+?"\}\]', '', self.info) #remove all team names (they have the same name: parameter as streamer names)
        self.streamers_names = re.findall('"name":"(.+?)"', self.info) #looks for the name of each streamer in the pile of info


        #run in a for to reduce all "live_user_NAME" values
        for name in self.streamers_names:
            if name.startswith("live_user_"):
                self.streamers_names.remove(name)

        #end method
        return self.streamers_names

    def get_streamer_mode(self, name):
        "Returns a streamers mode (on/off)"

        #start connection
        self.con = urllib2.urlopen(self.STREAMER_INFO + name)
        self.info = self.con.read()
        self.con.close()

    #check if stream is online or offline ("stream":null indicates offline stream)
    if self.info.count('"stream":null') > 0:
        return "offline"
    else:
        return "online"

main.py:

#imports:
from classes import *

#consts:
TWITCH_STREAMS = "https://api.twitch.tv/kraken/streams/?game=" #add the game name at the end of the link (space = "+", eg: Game+Name)
STREAMER_INFO  = "https://api.twitch.tv/kraken/streams/" #add streamer name at the end of the link
GAME = "League+of+Legends"

def main():
    #create an information object
    info = Information(TWITCH_STREAMS, GAME, STREAMER_INFO)

    streamer_list = [] #create a streamer list
    for name in info.get_game_streamer_names():
        #run for every streamer name, create a streamer object and place it in the list
        mode =  info.get_streamer_mode(name)
        streamer_name = Streamer(name, mode, 'http://twitch.tv/' + name)
        streamer_list.append(streamer_name)

    #this line is just to try and print something
    print streamer_list[0].name, streamer_list[0].mode


if __name__ == '__main__':
    main()

プログラム自体は完璧に動作しますが、本当に遅いです

何か案は?

4

2 に答える 2

9

プログラムの効率性は通常、80/20 ルール (または、一部の人々が 90/10 ルールまたは 95/5 ルールと呼ぶもの) に該当します。つまり、プログラムが実際に実行されている時間の 80% は、コードの 20% です。言い換えれば、コードに「ボトルネック」がある可能性があります。つまり、コードの小さな領域の実行速度が遅く、残りの部分の実行速度が非常に速いということです。目標は、そのボトルネック (またはボトルネック) を特定し、それを修正してより高速に実行することです。

これを行う最善の方法は、コードをプロファイリングすることです。これは、 loggingモジュールで特定のアクションが発生した時刻をログに記録していること、コメンターが提案したようにtimeitを使用していること、組み込みのプロファイラーを使用していること、または単にプログラムの非常に時点で現在の時刻を出力していることを意味します。最終的に、最も時間がかかっていると思われるコードの一部が見つかります。

経験上、I/O (ディスクからの読み取りやインターネット経由でのリソースへのアクセスなど) は、メモリ内の計算よりも時間がかかることがわかります。問題についての私の推測では、1 つの HTTP 接続を使用してストリーマーのリストを取得し、次に 1 つの HTTP 接続を使用してそのストリーマーのステータスを取得しています。10000 のストリーマーがあるとします。プログラムは、終了する前に 10001 の HTTP 接続を確立する必要があります。

これが実際に当てはまる場合、これを修正する方法がいくつかあります。

  • Twitch.TV の API に、ストリーマーごとに API を呼び出す必要がないように、ストリーミング モードでユーザーのリストを取得できる代替手段があるかどうかを確認してください。
  • 結果をキャッシュします。これは、最初の実行時に実際にプログラムを高速化するのに役立つわけではありませんが、1 分以内に 2 回目を実行した場合に結果を再利用できるようにすることはできるかもしれません。
  • 一度に少数のストリーマーのみを処理するようにアプリケーションを制限します。10000 個のストリーマーがある場合、10000 個すべてのストリーマーのモードを実際に確認するために、アプリケーションは正確に何を行うのでしょうか? おそらく、トップ 20 を取得するだけの方がよいでしょう。その時点で、ユーザーはキーを押して次の 20 を取得するか、アプリケーションを閉じることができます。多くの場合、プログラミングは単にコードを書くことではなく、ユーザーが望むものに対する期待を管理することです。これはペット プロジェクトのように見えるため、「ユーザー」が存在しない可能性があります。つまり、アプリの機能を自由に変更できます。
  • 複数の接続を使用します。現在、アプリはサーバーに 1 回接続し、結果が返されるのを待ち、結果を解析して保存し、次の接続で開始します。このプロセスには、0.5 秒かかる場合があります。250 のストリーマーがあった場合、それぞれに対してこのプロセスを実行すると、合計で 2 分強かかります。ただし、一度に 4 つ実行できれば、合計時間を 30 秒弱に短縮できる可能性があります。multiprocessingモジュールをチェックしてください。一部の API では、特定の時間に作成できる接続数に制限がある場合があることに注意してください。一度に 50 の接続をヒットすると、イライラして API へのアクセスが禁止される可能性があります。ここでは注意してください。
于 2013-02-24T17:09:43.700 に答える
4

ここでは、URL から返された json データを解析するために間違ったツールを使用しています。regexを使用してデータを解析するのではなく、デフォルトで提供されるjsonライブラリを使用する必要があります。これにより、プログラムのパフォーマンスが向上します

正規表現パーサーを変更する

#regular expressions to get all the stream names
        self.info = re.sub(r'"teams":\[\{.+?"\}\]', '', self.info) #remove all team names (they have the same name: parameter as streamer names)
        self.streamers_names = re.findall('"name":"(.+?)"', self.info) #looks for the name of each streamer in the pile of info

jsonパーサーへ

self.info = json.loads(self.info) #This will parse the json data as a Python Object
#Parse the name and return a generator 
return (stream['name'] for stream in data[u'streams'])
于 2013-02-24T16:58:23.037 に答える