Ref: Python之隊列模擬算法(打印機問題)【首先研究這個問題做爲開始】算法
定義一個任務隊列,來管理任務,而無需關心隊列的」任務類型"。app
# 自定義隊列類 class Queue(object):
def __init__(self): #初始化空隊列 self.items = [] def isEmpty(self): #是否爲空 return self.items == [] def enqueue(self, item): #入隊,索引爲0,即隊尾在左側 self.items.insert(0,item) def dequeue(self): #出隊,列表最後一個,即隊首在右側 return self.items.pop() def size(self): #查看隊列的大小 return len(self.items)
index不變,elem變化dom
queue.enqueue(queue.dequeue)函數
index變化,elem不變測試
position = index % Queue.size()spa
三個狀態:(1)接到一個新任務,就一個key: task timeRemaining(2)忙麼?(3)執行任務一秒鐘,更新任務狀態。.net
因此,打印機類的」執行任務「,外層是一個」秒針滴答」的循環。3d
# 打印機類 須要實時監測是否正在執行打印任務 class Printer(object):
def __init__(self, ppm): self.pagerate = ppm # 頁面打印速率:打印一張須要多少秒 self.currentTask = None # 初始化當前任務 self.timeRemaining = 0 # 初始化剩餘時間 # 計算正在執行的打印任務的剩餘時長,即減去當前秒(1秒時長)後的時長 def tick(self): if self.currentTask != None: # 正在執行打印任務 self.timeRemaining = self.timeRemaining - 1 # 去除當前秒的任務剩餘時長 if self.timeRemaining <= 0: # 當前打印任務結束後 self.currentTask = None # 在一次任務結束後將打印機設爲空閒 # 對外接口:打印機是否忙碌 def busy(self): if self.currentTask != None: # 當前打印機有任務,則 return True # 忙碌 else: # 當前打印機無任務,則 return False # 空閒 # 進入下一個打印任務 def startNext(self, newtask): self.currentTask = newtask self.timeRemaining = newtask.getPages() * 60/self.pagerate # 新任務須要的時間秒數: (有幾張 * 一張須要多少秒)
建立一個 「隨機大小「 的任務;並設定好 「生日」。code
類中的只讀屬性,能夠考慮使用@property。blog
# 一個單獨的打印任務 class Task(object):
def __init__(self,time): self.timestamp = time # 出生時間:任務被建立和被放入打印隊列時的時間節點 self.pages = random.randrange(1,21) # 隨機大小:隨機生成1-20頁的單個任務的打印頁數 # 對外接口:獲取時間節點,此處沒用到。 def getStamp(self): return self.timestamp # 對外接口:獲取頁數 def getPages(self): return self.pages # 已經等待了多久;用於檢索任務開始打印前在隊列中的等待時長 def waitTime(self, currenttime): return currenttime - self.timestamp
例如:評估下」一小時內「 使用一臺 「每分鐘打印五張」 打印機的狀況,進行模擬。
每一秒,要考慮兩個事情:(1)有新任務?(2)能處理新任務?(3)打印機處理一次。
# 指定時長、指定打印速率下的打印函數 def simulation(numSeconds, pagesPerMinute):
labprinter = Printer(pagesPerMinute) # 實例化打印機類,參數爲頁/分鐘 printQueue = Queue() # 建立打印隊列 waitingtimes = [] # 初始化等待時長列表
# 模擬:時間是 一秒一秒 地流逝,每一秒都要考慮兩個事情。 for currentSecond in range(numSeconds): #在指定時長numSeconds內的當前秒時 # (a) 有新來的打印任務嚒?
if newPrintTask(): #如有打印任務,則 task = Task(currentSecond) #建立打印任務,並記錄當前時間節點 printQueue.enqueue(task) #將該打印任務入隊
# (b) 若打印機不忙碌,且打印隊列不爲空,則 if (not labprinter.busy()) and (not printQueue.isEmpty()): nexttask = printQueue.dequeue() #出隊 waitingtimes.append(nexttask.waitTime(currentSecond)) #將該任務等待時長加入等待列表 labprinter.startNext(nexttask) #打印該任務
# (c) 打印機執行一次 labprinter.tick() #計算正在執行的打印任務的剩餘時長,並在一次任務結束後將打印機設爲空閒
averageWait = sum(waitingtimes) / len(waitingtimes) #平均等待時長 print("Average Wait %6.2f secs %3d tasks remaining." % (averageWait, printQueue.size()))
條件判斷之模擬,1/180的機率去作一件事。
# 使用隨機函數建立打印任務 def newPrintTask(): num = random.randrange(1, 181) #生成隨機數,平均3分鐘有一個任務 if num == 180: return True #有打印任務 else: return False #沒有打印任務
if __name__ == '__main__': for i in range(10): #獲取10次打印狀況 simulation(3600, 5) #獲取1小時內,每分鐘打印5張的打印狀況
Output:
Average Wait 58.35 secs 0 tasks remaining. Average Wait 85.43 secs 0 tasks remaining. Average Wait 83.68 secs 4 tasks remaining. Average Wait 107.12 secs 0 tasks remaining. Average Wait 71.05 secs 0 tasks remaining. Average Wait 30.77 secs 3 tasks remaining. Average Wait 143.09 secs 0 tasks remaining. Average Wait 195.75 secs 4 tasks remaining. Average Wait 265.95 secs 1 tasks remaining. Average Wait 70.94 secs 0 tasks remaining.
首先,這是一個 「模擬現實」 並作出評估的問題,思惟模式具備必定的實際意義。
Input 端的兩個隨機特性;
代碼樣例以下:
for currentSecond in range(numSeconds): if random.randrange(0, 180) == 180 # 隨機輸入 task = Task(currentSecond) # 隨機負載 printQueue.enqueue(task)
class Task(object): def __init__(self,time): self.timestamp = time self.pages = random.randrange(1,21) # 隨機負載
End.