1

私はPythonプログラミングにかなり慣れていませんが、スレッドは私の専門分野ではありません。私はここの人々が私を助けてくれることを願っている問題を抱えています。

タスク:私の修士論文の一部として、マルチプレイヤー機能を含む複合現実ゲームを作成する必要があります。私のゲームデザインでは、各プレイヤーは一連のトラップを設定できます。各トラップは、30秒などの特定の期間アクティブになります。すべてのプレーヤーで一貫したゲーム状態を維持するには、Pythonで実装されているサーバー側で常にチェックを行う必要があります。

プレーヤーが新しいトラップを設定するたびにPythonスレッドを開始し、スレッドでタイマーを実行することにしました。この部分はすべて問題ありませんが、実際の問題は、この特定のトラップの時間が経過したことをメインスレッドに通知する必要がある場合に発生します。これにより、クライアント(Androidデバイス)と同じ通信を行うことができます。

タスクが完了したときにキューを作成してキューに情報を挿入しようとしましたが、タスクが完了するまでメインスレッドが保留になるため、queue.join()を実行できません。これは必要なことでも、必要なことでもありません。私の場合、メインスレッドは常にクライアントと通信しているので、それが停止すると、プレーヤーとのすべての通信が停止するので理想的です。

タイマーを実行しているセカンダリスレッドが、時間がなくなるとすぐにメインスレッドに通知し、トラップのIDを送信して、この情報をAndroidクライアントに渡すことができるようにする必要があります。それを削除します。どうすればこれを達成できますか?

膨大な数のスレッドを開始せずにこのタスクを実行する方法に関するその他の提案も歓迎します。.:):)

助けてくれてありがとう。

乾杯

4

3 に答える 3

2

私はついにPythonで書かれた素敵な小さなタスクスケジューラを見つけました。これは実際には非常に軽く、子スレッドが値をメインスレッドに戻すことができるコールバックメカニズムを使用して後でイベントをスケジュールするのに非常に便利ですメインスレッドにそのステータスと、ジョブが正常に実行されたかどうかを通知します。

質問の機能と同様の機能が必要で、スレッドを操作したくない人は、このスケジューラを使用してイベントをスケジュールし、イベントが完了したときにコールバックを取得できます。

こちらがAPSchedulerへのリンクです

于 2012-06-21T12:18:33.677 に答える
1

タイマーをすべてメインスレッドで実行する方が簡単な場合があります。新しいタイマーを追加し続けるタイマーのリストを用意してください。各タイマーは実際には何もしませんタイマーがオフになる時間があるだけです。これは、リアルタイムよりも任意の「ラウンド」で作業する方が簡単ですが、それでも実行可能です。間隔ごとに、メインループはそれらすべてをチェックし、有効期限が切れる時間(または過去の時間)かどうかを確認する必要があります。有効期限が切れている場合は、リストから削除します(もちろん、リストからアイテムを削除する場合は注意が必要です。繰り返します-期待どおりに動作しない可能性があります)。

タイマーがたくさんあり、プロファイリングを行うことで、間隔ごとにすべてのタイマーを実行すると時間がかかりすぎることがわかった場合、単純な最適化は、タイマーをヒープに保持することです。これにより、タイマーがソートされたままになります。あなたはまだ期限切れになっていない最初のものの後で、残りのどれも持っていないことを知っています。何かのようなもの:

while True:
    if not q:
       break
    timer = heapq.heappop(q)
    if timer.expiry <= currenttime:
       # trigger events
    else:
       heapq.heappush(q)
       break

これでも、不要なポップ/プッシュのペアが1つ必要になりますが、どのようにすればよいかわかりません。繰り返しになりますが、次のようなことを行います。

for timer in q:
    if timer.expiry <= currenttime:
       heapq.heappop(timer)
       # trigger events
    else:
       break

リストイテレータ(何らかの理由heapqで本格的なheapqクラスが存在するのではなく、シーケンスで機能し、副作用を使用する関数)は、現在のインデックスを削除すると、現在のインデックスを追跡することで機能するため、微妙なバグが発生する可能性があります要素の場合、1つのインデックスの後にすべてを左にプッシュし、次のインデックスをスキップすることになります。

唯一の重要なことはcurrenttime、メインループの各間隔で一貫して更新され(または、システムクロックに基づいてリアルタイムで更新されるように設定されている場合)、timer.expiry同じ単位で測定されることです-コンセプトがある場合'ラウンド'の、そしてトラップは6ラウンド続きます、それが置かれるとき、あなたはするでしょうheapq.heappush(q, Timer(expiry=currenttime+6)

マルチスレッドの方法で実行したい場合は、クリーンアップのためにプロデューサー/コンシューマーキューを作成する方法が機能します。使用する必要はありませんQueue.join()。代わりに、スレッドのタイマーがなくなると、を呼び出してから終了しますq.put()。メインループはを使用します。これはブロックq.get(False)を回避するかq.get(True, 0.1)、最大0.1秒間ブロックします。タイムアウトは任意の正の数にすることができます。クライアントが気付くのに十分な時間ブロックすることと、時間どおりにキューに入るのを逃しただけでイベントが遅れて発生することとの間の最良のトレードオフのために、慎重に調整してください。

于 2012-06-18T09:44:15.870 に答える
0

メインスレッドは、キューと、キューからタスクをプルする一連のワーカースレッドを作成します。キューが空である限り、すべてのワーカースレッドがブロックされ、何も実行されません。タスクがキューに入れられると、ランダムなワーカースレッドがタスクを取得し、ジョブを実行して、準備ができるとすぐにスリープします。そうすれば、新しいワーカースレッドを作成せずに、スレッドを何度も再利用できます。

スレッドを停止する必要がある場合は、キューをブロックする代わりにシャットダウンするようにスレッドに指示するkillオブジェクトをキューに入れます。

于 2012-06-18T09:53:28.800 に答える