佇列應用

模擬列印任務

本投影片含有強烈不專業成份
如服用時有過敏不適等症狀
請立即停用並找專業教師治療矯正

模擬?

  • 使用某種方法偽裝一個行為

  • 藉由這種偽裝得到/驗證行為導致的結果

  • 被模擬的情境設計需要考慮情境中的變因

  • 可以凸顯/屏蔽某些變因交互比對結果

以印表機列印任務為例

  • 單純要模擬印表機工作的話

  • 需要有一台可以接收列印任務進行列印的印表機

  • 需要有可以被列印的列印任務

  • 至於誰給列印任務不太重要

  • 怎麼給列印任務好像是個問題,但先擱一下

列印任務

  • 產生時間

  • 頁數

  • 內容在這個情境中不太需要被考慮

class PrintTask:
    """PrintTask
    A class to represent a task that will sent to a printer, 
    it include what time it be created, and how many pages in it.
    """
    
    def __init__(self, pages):
        self.create_time = datetaime.time()
        self.pages = pages
   
    def get_pages(self):
        return selg.pages

    def get_create_time(self):
        return self.create_time

印表機

  • 取得任務

  • 執行列印

  • 可以表現狀態的改變

  • 需要另外有能力判斷是否在執行任務中還是閒置中

class Printer:
    """Printer
    A class simulate a printer has ppm as attribute 
    and some abilities to get and do PrintTask.
    """
    
    def __init__(self, ppm):
        self.task_queue = Queue()
        self.current_task = None
        self.ppm = ppm
        self.remain_time = 0

    def add_task(self, task):
        self.task_queue.enqueue(task)

    def tick(self):
        if not self.current_task is None:
            self.remain_time -= 1
            if 0 >= self.remain_time:
                self.pick_task()
        else:
            self.pick_task()

    def is_busy(self):
        return False if self.current_task is None else True
        
    def pick_task(self):
        if 0 < self.task_queue.size():
            self.current_task = self.task_queue.dequeue()
            self.remain_time = self.current_task .get_pages() * 60 // self.ppm
            print('Get Next Task: has %d pages will take %d seconds' % (self.current_task .get_pages(), self.remain_time))
        else:
            self.current_task = None
            self.remain_time = 0

情境設計

  • 先單純一點

  • 驗證ppm與remain_time的模擬是否正確

  • 看有沒有照順序跑

  • 給定所有變因跑完看時間結果

def scenario_simple(ppm, pages_list):
    """scenario_simple
    A simple scenario to simulate set tasks with pages in a list
    to verify queue order, and ppm in print, check the tick count
    """
    
    expect_time = 0
    printer = Printer(ppm)
    for pages in pages_list:
        expect_time += pages * 60 // ppm
        printer.add_task(PrintTask(pages))
        
    printer.tick()
        
    real_time = 0
    while printer.is_busy():
        real_time += 1
        printer.tick()
    
    print('Real take time: %d, Expect take time: %d' % (real_time, expect_time))
    

scenario_simple(10, [5, 20, 25, 10])
scenario_simple(4, [10, 4, 30, 8, 25, 5, 2])
scenario_simple(12, [6, 18, 24, 2, 10, 27, 8])

看看教材想幹嘛

  • 給定一個時間

  • 隨機給列印任務,頁數也是隨機

  • 看在固定的列印速度下平均等待時間為何

def scenario_complex(time_num, ppm):
    """scenario_complex
    A complex scenario to simulate set random tasks with random pages 
    to chech the wait time for a fixed page rate
    """
    
    printer = Printer(ppm)
    wait_items = []
    
    for current_second in range(time_num):
        if new_print_task(): printer.add_task(PrintTask(current_second, random.randrange(1,21)))
    
        temp = printer.tick()
        if not temp is None:
            wait_items.append(current_second - temp.get_create_time())
    
    average_wait=sum(wait_items)/len(wait_items)
    print("Average Wait %6.2f secs %3d tasks remaining."%(average_wait,printer.get_task_queue().size()))

        
def new_print_task():
    num = random.randrange(1,181)
    return True if num == 180 else False


for i in range(10):
    print("======Start Simulate %d=========" % (i+1))
    scenario_complex(3600,5)
    print("======End Simulate %d=========" % (i+1))
    print()

原本的設計不夠用

  • 還需要再有一個元件表現任務佇列

  • 從原本的印表機拆出來讓情境可以方便取得資訊

  • 也需要符合情境的產生時間

小結

  • 注重於自己需要的資訊

  • 將其抽象出來

  • 將抽象概念實作出來

  • 不要太拘泥於一個方向,多方嘗試

QueueSimulatePrintTask

By Ted Wu

QueueSimulatePrintTask

  • 1,452