2

イベント駆動型のチャットボットを持っていて、スパム対策を実装しようとしています。アプリケーションの残りの部分をブロックすることなく、悪い行動をしているユーザーを一定期間沈黙させたいです。

機能しないものは次のとおりです。

if user_behaving_badly():
  ban( user )
  time.sleep( penalty_duration )  # Bad! Blocks the entire application!
  unban( user )

理想的には、user_behaving_badly() が true の場合、ユーザーを禁止するだけの新しいスレッドを開始し、しばらくスリープしてユーザーの禁止を解除すると、スレッドが消えます。

これによると、次を使用して目標を達成できます。

if user_behaving_badly():
  thread.start_new_thread( banSleepUnban, ( user, penalty ) )

「単純」は通常「良い」の指標であり、これは非常に単純ですが、スレッドについて私が聞いたすべてのことは、スレッドが予期しない方法であなたを噛む可能性があると言っていました. 私の質問は次のとおりです。アプリケーションの残りの部分をブロックせずに単純な遅延ループを実行するには、これよりも良い方法はありますか?

4

5 に答える 5

5

禁止ごとにスレッドを開始する代わりに、禁止を優先キューに入れ、単一のスレッドにスリープと禁止解除を実行させます

このコードは、期限が切れる最も早い禁止をすばやく見つけることができる heapq と、ユーザーが名前で禁止されているかどうかをすばやく確認できるようにする dict の 2 つの構造を保持します。

import time
import threading
import heapq

class Bans():
    def __init__(self):
        self.lock = threading.Lock()
        self.event = threading.Event()
        self.heap = []
        self.dict = {}
        self.thread = threading.thread(target=self.expiration_thread)
        self.thread.setDaemon(True)
        self.thread.start()

    def ban_user(self, name, duration):
        with self.lock:
            now = time.time()
            expiration = (now+duration) 
            heapq.heappush(self.heap, (expiration, user))
            self.dict[user] = expiration
            self.event.set()

    def is_user_banned(self, user):
        with self.lock:
            now = time.time()
            return self.dict.get(user, None) > now

    def expiration_thread(self):
        while True:
            self.event.wait()
            with self.lock:
                next, user = self.heap[0]
                now = time.time()
                duration = next-now
            if duration > 0:
                time.sleep(duration)
            with self.lock:
                if self.heap[0][0] = next:
                    heapq.heappop(self.heap)
                    del self.dict(user)
                if not self.heap:
                    self.event.clear()

次のように使用されます。

B = Bans()
B.ban_user("phil", 30.0)
B.is_user_banned("phil")
于 2011-10-15T02:52:13.557 に答える
3

なぜスレッドするのですか?

do_something(user):
  if(good_user(user)):
    # do it
  else
    # don't

good_user():
  if(is_user_baned(user)):
    if(past_time_since_ban(user)):
      user_good_user(user)
  elif(is_user_bad()):
    ban_user()

ban_user(user):
  # add a user/start time to a hash

is_user_banned()
  # check hash
  # could check if expired now too, or do it seperately if you care about it

is_user_bad()
  # check params or set more values in a hash
于 2011-10-15T02:22:02.953 に答える
3

次のように、スレッドタイマー オブジェクトを使用します。

t = threading.Timer(30.0, unban)
t.start() # after 30 seconds, unban will be run

その後、unban のみがスレッドで実行されます。

于 2011-10-15T02:29:07.823 に答える
0

GUIを使用している場合、
ほとんどのGUIモジュールにはタイマー機能があり、すべての厄介なマルチスレッド処理を抽象化し、指定された時間後にコードを実行できますが、残りのコードは実行できます。

たとえば、Tkinter には「after」機能があります。

于 2011-10-15T02:26:20.030 に答える
0

これは言語に依存しませんが、物事を追跡するスレッドを検討してください。スレッドは、「username」や「banned_until」などのデータ構造をテーブルに保持します。スレッドは常にバックグラウンドで実行され、テーブルをチェックします。banned_until の有効期限が切れている場合、ユーザーのブロックを解除します。他のスレッドは正常に進行します。

于 2011-10-15T02:11:22.317 に答える