0

それで、最初に。これが私のサーバーエンジンです。gilmud.py

さて、これが私の以前の小説サイズの投稿の短縮版です。

上記のリンクは、MUD用のPythonサーバーエンジンです。行73-75、および359に注意

self.tickThread = threading.Thread(None, self.runTicks, None, ())
self.tickThread.start()

..。

def runTicks(self):
    while self.running:
        time.sleep(.1)
        for thing in Thing.List.values():
            if thing:
                if "person" in thing.attrs:
                    if "spawner" in thing.attrs:
                        thing.tick()

恐らく、およそ100人のプレイヤーと2000人のmob/npcsの「ライフ」に必要なものを与える恐ろしい方法がわかるでしょう。tick()は、移動するのか、拾うのか、アイテムを拾うのか、戦闘中なのか、ターゲットにされているのかなどをチェックします。もちろん、自動化されたものを除いて、プレイヤーにも同じことが言えます。

パフォーマンスを向上させるために、このモジュールの一部またはすべて、たとえばC ++を書き直す方法はありますか?現在、必要な.1秒のティックは、現在の方法でpythonを使用して約3秒です。

(また、いくつかの異なるスレッドタイプとスタックレスを試しました。何もうまくいきませんでした)。

助けてくれてありがとう!どんなアドバイスも大歓迎です!

4

4 に答える 4

3

コードには多くの非効率性があります。

メソッドだけを見るとPerson.tick

交換

for spell in self.spellTimers:
            self.spellTimers[spell]['tick'] += 1

for spell_timer in self.spellTimers.itervalues():
            spell_timer['tick'] += 1

値ごとに少なくとも 2 つ少ない dict ルックアップで同じこと

交換

for thing in Thing.List.values():
            if thing:
                if "person" in thing.attrs:
                    if "spawner" in thing.attrs:
                        thing.tick()

for thing in Thing.List.itervalues():
            if thing and "person" in thing.attrs 
                     and "spawner" in thing.attrs:
                    thing.tick()

(わかりました、それほど速くはないかもしれませんが、私はそれが好きです)

得る:

from spells import cast,spellmaker

tick() メソッドから出て、ファイルの先頭に

交換:

#spell cooldown timer
self.timers['cooldown'] -= 1
if self.timers['cooldown'] < 0:
    self.timers['cooldown'] = 0

と:

#spell cooldown timer
self.timers['cooldown'] = max(0, self.timers['cooldown']-1)

あなたはそれをたくさんします。次のようなコードがたくさんあります

    #Check if self is doing ranged attack, and then increase timer (ready their weapon)
    self.timers['ranged'] += 1
    if self.timers['ranged'] >= int((self.stats['dex']*-1.1)+60+2):
        self.timers['ranged'] = int((self.stats['dex']*-1.1)+60+1)
    if self.timers['ranged'] == int((self.stats['dex']*-1.1)+60):
        self.timers['ranged'] = int((self.stats['dex']*-1.1)+60+1)

2 番目 の条件は、最初の条件が true の場合、2 番目の条件が true になることはありifません。elif

アクセスするたびself.somedict['name']に、2 つの dict ルックアップを行っていることに注意してください (オーバーヘッドはさらに増える可能性がありますが、経験則として使用してください)。行ごとに dictlookup がある場合は、コードを「一時」ローカル変数に割り当てることでコードを高速化します。

コードを読み進めると、上記のいずれかのように 1 週​​を入れてインライン化します。申し訳ありませんが、すべてを通過することはできません。

于 2012-07-18T00:01:10.670 に答える
1

You've got a lot of great specific feedback already so I'll only add an observation from a mudder's perspective. There are a couple of large mud projects that use Python without speed issues (for example Evennia), so I'm confident in saying you're better off refactoring the code you have than dropping down to C.

于 2012-07-18T02:44:54.367 に答える
1

関連するPythonコードを数行投稿していないので、Pythonについて知っておくべきことの1つは、同等のPythonスタイルで実行できるのに、Cスタイルでコードを記述できることです。多くの場合、関連するコードは見たことがありませんが、たとえばリスト内包表記を作成する代わりに、古いスタイルのデータ処理では、よりPythonのスタイルを使用するよりも時間がかかります。

小さな例を投稿し、物事をスピードアップするためのより良い方法があるかどうかを尋ねることで、Pythonicスタイルを取得するためのヘルプを得ることができます-そしてところで私はたくさんの助けが必要です-。また、時間をキャプチャするためにコードをインストルメント化することもできます。

于 2012-07-17T20:44:49.687 に答える
1

その一部を C++ などで書き直すことは可能ですが、ループが 2000 個程度のアイテムを処理するのに 3 秒かかる場合は、むしろコーディング方法に重大な問題がある可能性が高いと思います。 Python自体に固有の問題よりも。

したがって、最初に、他の回答/コメントで行われたプロファイリングの推奨事項を2番目にしたいと思います-これは、ループのどこに常に消えているかを正確に伝えるための最良の方法です. Python で提供されているプロファイラーに関するドキュメントは、こちらで入手できます

次に、標準の python ディストリビューションを使用している場合は、可能であればスレッドから離れることを検討します。Python のデフォルトの実装にはグローバル インタープリタ ロックがあり、解釈された Python コードが真に並列で実行されるのを防ぎ、最初からスレッドに煩わされることの多くの利点を取り除きます (場合によっては、実際に処理が遅くなります)。

第三に、あなたが投稿したコードについていくつかの小さなアドバイスを提供できます。プロファイラーを使用して私の疑いを確認するのが最善ですが (そして、私が気付いていない問題領域を見つけるために - そこにはかなり多くのコードがあるようです)、これはおそらく次の場合に役立つと思います少しでも:

あなたの for ループfor thing in Thing.List.values():では、おそらくThing.List.itervalues(). これは、値の完全なリストを割り当てるのではなく、値に対して反復子を返します。リストを反復しながら辞書に追加または削除することを計画していない限り、リストの割り当ては不要であり、辞書に2000個程度のアイテムがある場合は速すぎない可能性があります。このアドバイスは、反復中にエントリの追加/削除を計画していないと仮定して、コード内の辞書を反復している他の場合にも適用されます (.iteritems()の代わりに.items(),の.iterkeys()代わりに使用します.keys())。

time.sleepまた、すべての反復を呼び出すのではなく、別のタイミング メソッドを検討することもできます。私が見ることができる2つの問題があります-主にtime.sleep(.1)、スリープが0.1秒続くことを実際に保証するものではなく、処理にかかる時間を考慮していないためです。たとえば、処理に 0.05 秒かかってから 0.1 秒スリープすると、実際には 0.15 秒の間隔があり、処理が激しくなるにつれてこのギャップは大きくなります。具体的な提案はありませんが、少なくとも数値を渡すときに処理時間を考慮したい場合がありますtime.sleep

最後に、ある時点でコード レビュー スタック交換の使用を検討することをお勧めします。ゲーム エンジン全体をレビューしたいと思う人はいないと思いますが、フィードバックが必要なコードや改善できると思われるコードのチャンクを配置するのに適しているようです。

于 2012-07-17T22:18:15.957 に答える