2011-10-15 48 views
2

我有一個事件驅動的聊天機器人,我試圖實施垃圾郵件防護。我想要沉默一段時間內表現糟糕的用戶,而不會阻塞應用程序的其餘部分。運行Python延遲循環最痛苦的方式

這裏是行不通:

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

理想的情況下,如果user_behaving_badly()是真實的,我要開始一個新的線程它什麼也不做,但禁止用戶,然後睡了一會兒,黑名單中刪除用戶,然後該線程消失。

According to this我可以使用下面的完成我的目標:

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

「簡單」通常是「好」的指標,這是很簡單的,但就我聽到的關於線程曾表示,他們會以意想不到的方式咬你。我的問題是:有沒有比這更好的方式來運行一個簡單的延遲循環而不會阻塞應用程序的其餘部分?

+0

這是一個客戶端 - 服務器APPLICA重刑? – NullUserException

+0

是的,它是客戶端服務器。我無法控制客戶。 –

回答

2

使用一個線程timer object,像這樣:

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

然後取消禁止僅在線程中運行。

0

這是語言不可知的,但考慮一個線程來跟蹤的東西。線程在表中保留一個類似「username」和「banned_until」的數據結構。線程始終在後臺檢查表中運行,如果banned_until已過期,它將取消阻止用戶。其他線程正常進行。

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 
+1

+1保持簡單,避免線程'冷靜'。 –

0

如果您使用的是圖形用戶界面,
大多數GUI模塊有一個計時器功能,可以抽象所有呸多線程的東西, 和給定的時間後執行代碼, 但仍然允許的其餘部分代碼被執行。例如,Tkinter具有'後'功能。

5

,而不是啓動一個線程每個禁令,把禁令的優先級隊列,並有一個單獨的線程做睡眠和unbanning

這段代碼有兩隻結構一個heapq,允許它快速找到最快禁令到期和字典,使其可以快速檢查,如果用戶是通過名

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") 
+0

這是兩個很好的答案之一,我希望我可以接受他們兩個。 –