2014-05-09 52 views
3

我在寫一個迷你遊戲,它允許我練習我的python線程技能。遊戲本身涉及定時炸彈和擁有它們的城市。Python線程設計

這裏是我的代碼:

class City(threading.Thread): 

    def __init__(self, name): 
     super().__init__() 
     self.name = name 
     self.bombs = None 
     self.activeBomb = None 
     self.bombID = 0 
     self.exploded = False 

    def addBomb(self, name, time, puzzle, answer, hidden=False): 
     self.bombs.append(Bomb(name, self.bombID, time, puzzle, answer, hidden)) 
     self.activeBomb.append(self.bombID) 
     self.bombID += 1 

    def run(self): 
     for b in self.bombs: 
      b.start() 
     while True: 
      # listen to the bombs in the self.bombs # The part that I dont know how 

      # if one explodes 
      # print(self.name + ' has been destroyed') 
      # break 
      # if one is disarmed 
      # remove the bombID from the activeBomb 
      # if all bombs are disarmed (no activeBomb left) 
      #  print('The city of ' + self.name + ' has been cleansed') 
      # break 


class Bomb(threading.Thread): 

    def __init__(self, name, bombID, time, puzzle, answer, hidden=False): 
     super(Bomb, self).__init__() 
     self.name = name 
     self.bombID = bombID 
     self._timer = time 
     self._MAXTIME = time 
     self._disarmed = False 
     self._puzzle = puzzle 
     self._answer = answer 
     self._denoted = False 
     self._hidden = hidden 

    def run(self): 
     # A bomb goes off!! 
     if not self._hidden: 
      print('You have ' + str(self._MAXTIME) 
        + ' seconds to solve the puzzle!') 
      print(self._puzzle) 
     while True: 
      if self._denoted: 
       print('BOOM') 
       // Communicate to city that bomb is denoted 
       break 
      elif not self._disarmed: 
       if self._timer == 0: 
        self._denoted = True 
       else: 
        self._timer -= 1 
        sleep(1) 
      else: 
       print('You have successfully disarmed bomb ' + str(self.name)) 
       // Communicate to city that this bomb is disarmed 
       break 

    def answerPuzzle(self, ans): 
     print('Is answer ' + str(ans) + ' ?') 
     if ans == self._answer: 
      self._disarmed = True 
     else: 
      self._denotaed = True 

    def __eq__(self, bomb): 
     return self.bombID == bomb.bombID 

    def __hash__(self): 
     return id(self) 

目前,我不知道什麼是城市類的好方法,有效跟蹤的 炸彈狀態。

首先想到我是使用一個for循環有市檢查所有的炸彈在 市,但我發現它太愚蠢和低效

因此,這裏的問題:

實施炸彈和城市的最有效方式是什麼,以便城市立即知道炸彈的狀態變化,而不必每秒都檢查一次?

PS:我不打算用這個程序來襯托真實的炸彈,所以放鬆:d

回答

1

使用隊列的好例子。這就是所謂的生產者 - 消費者模式的一個例子。

工作線程將一直運行,直到完成主程序(這是守護程序部分和「while True」的用途)。他們將認真監控in_queue的工作包。他們會處理包裹,直到沒有人離開。所以當in_queue被加入時,你的工作線程的工作就完成了。這裏的out_queue是一個可選的下游處理步驟。因此,您可以將工作線程中的棋子組裝成摘要表單。當他們在功能中時很有用。

如果你需要一些輸出,就像每個工作線程將打印結果輸出到屏幕或寫入到一個單一的文件,不要忘了旗語使用!否則,你的輸出會絆倒對方。

祝你好運!

from threading import Thread 
import Queue 

in_queue = Queue.Queue() 
out_queue = Queue.Queue() 

def work(): 
    while True: 
     try: 
      sonId = in_queue.get() 
     ###do your things here 
      result = sonID + 1 

     ###you can even put your thread results again in another queue here 
      out_queue.put(result) ###optional 


     except: 
      pass 
     finally: 
      in_queue.task_done() 

for i in range(20): 

    t = Thread(target=work) 
    t.daemon = True 
    t.start() 


for son in range(10):  
    in_queue.put(son) 


in_queue.join() 

while not out_queue.empty(): 

    result = out_queue.get() 

    ###do something with your result here 

    out_queue.task_done() 

out_queue.join() 
1

做這樣的事情的標準方法是使用一個隊列 - 一個線程手錶隊列和等待一個要處理的對象(允許它快樂地閒置),另一個線程將項目推送到隊列中。

Python有the queue moduleQueue in 2.x)。在你的監聽器線程中建立一個隊列,並在其上建立get() - 這會阻塞,直到有人接受。

在另一個線程中,當發生相關事件時,將其推送到隊列中,並且偵聽器線程將喚醒並處理它。如果你在一個循環中做到這一點,你有你想要的行爲。

0

最簡單的方法是使用調度程序庫。例如。 https://docs.python.org/2/library/sched.html。使用這個,你可以簡單地安排炸彈在他們離開時調用一個函數或方法。如果你不想了解線程,這就是我會推薦的。

E.g.

import sched 
s = sched.scheduler(time.time, time.sleep) 
class Bomb(): 
    def explode(self): 
     if not self._disarmed: 
      print "BOOM" 

    def __init__(self, time): 
     s.enter(self._MAXTIME, 1, self.explode) 

但是,那樣你就不會學習線程。

如果你真的想直接使用線程,那麼你可以簡單地讓炸彈調用睡眠,直到他們的時間到了。例如。

class Bomb(threading.Thread) 
    def run(self): 
     time.sleep.(self._MAXTIME) 
     if not self._disarmed: 
      print "BOOM" 

但是,這不是處理線程的好方法,因爲線程會阻塞您的應用程序。在停止線程之前,您將無法退出應用程序。你可以通過使線程成爲守護線程來避免這種情況。 bomb.daemon = True

在某些情況下,處理這種情況的最好方法是每秒鐘「醒來」並檢查世界的狀態。當線程停止時需要執行一些清理操作時,可能會出現這種情況。例如。您可能需要關閉文件。檢查每一秒可能看起來很浪費,但它實際上是處理這些問題的正確方法。現代臺式電腦大多閒置。每秒鐘中斷幾毫秒不會導致他們太多的汗水。

class Bomb(threading.Thread) 
    def run(self): 
     while not self._disarmed: 
      if time.now() > self.time_to_explode: 
       print "BOOM" 
       break 
      else: 
       time.sleep.(1) 
0

開始之前「練習與Python線程」,我想了解Python的線程模型是很重要的 - 它是Java線程模型,但配備了更嚴格的選擇:

https://docs.python.org/2/library/threading.html

該模塊的設計鬆散地基於Java的線程模型。 但是,在Java爲每個對象創建鎖和條件變量基本行爲 的情況下,它們是Python中的單獨對象。 Python的線程 類支持Java的Thread類行爲的一個子集; 目前沒有優先級,沒有線程組,並且線程 不能被銷燬,停止,掛起,恢復或中斷。 Java的Thread類的靜態方法在實現時映射到 模塊級函數。

鎖定在單獨的對象中,而不是按照下圖所示的每個對象,即使訪問不同的對象也意味着較少的獨立調度 - 因爲甚至可能需要相同的鎖。

Java Threading Model

對於一些Python實現 - 線程是不是真的完全併發:

http://uwpce-pythoncert.github.io/EMC-Python300-Spring2015/html_slides/07-threading-and-multiprocessing.html#slide-5

線程是進程中的實體可以安排 執行

線程是輕量級進程,運行在操作系統的地址空間中 過程。

這些線程共享內存和進程的狀態。這個 允許多個線程訪問同一範圍內的數據。

Python的線程是真正的OS級線程

線程不能獲得多個處理器 由於全局解釋器鎖(GIL)

http://uwpce-pythoncert.github.io/EMC-Python300-Spring2015/html_slides/07-threading-and-multiprocessing.html#slide-6

的性能優勢,並在(從以上幻燈片):

GIL in action