【问题标题】:How to create a simulated printer in Python?如何在 Python 中创建模拟打印机?
【发布时间】:2016-02-18 03:06:38
【问题描述】:

我正在尝试使用链接队列来模拟打印机来管理打印作业。一个打印作业将按照提交的顺序处理,并且有 2 台打印机。每个打印作业都有许多页,并且会在用户选择的特定周期内占用打印机。

例如,如果有 3 个作业,作业 1(5 页)、作业 2(7 页)和作业 3(13 页),在 6 个周期(打印页)之后,一台打印机上就会有作业 2还剩 1 页,另一页上还有作业 3,还剩 12 页。

我能够处理队列中的 2 个作业,但我不知道如何处理第三个作业,因为我希望只有在打印机可用时才处理第三个作业。

【问题讨论】:

标签: python printing


【解决方案1】:

这是您所找到的最清晰的解决方案 - 三个类(PrintJobJobQueuePrinter)和一个用于模拟的 main() 函数:

class PrintJob:
    def __init__(self, name, pages):
        self.name = name
        self.pages = pages
        self.remaining = pages

    def tick(self):
        if self.remaining:
            self.remaining -= 1
        print("Job {}: {} / {} pages remain".format(self.name, self.remaining, self.pages))

    def is_done(self):
        return self.remaining == 0

class JobQueue:
    def __init__(self):
        self.jobs = []

    def enqueue(self, job):
        self.jobs.append(job)

    def dequeue(self):
        return self.jobs.pop(0)

    def is_empty(self):
        return not self.jobs

class Printer:
    def __init__(self, name, job_queue):
        self.name = name
        self.job_queue = job_queue
        self.current_job = None

    def tick(self):
        # make sure we have a job to work on
        if self.current_job is None:
            if self.job_queue.is_empty():
                print("Printer {} is idle".format(self.name))
                return
            else:
                self.current_job = self.job_queue.dequeue()
                print("Printer {} got job {}".format(self.name, self.current_job.name))
        # print!
        print("Printer {} is printing...".format(self.name))
        self.current_job.tick()
        # see if job is finished
        if self.current_job.is_done():
            print("Printer {} finished job {}".format(self.name, self.current_job.name))
            self.current_job = None

    def is_idle(self):
        return self.current_job is None

def main():
    # create job queue and two printers
    jobs = JobQueue()
    p1 = Printer(1, jobs)
    p2 = Printer(2, jobs)

    # add jobs
    jobs.enqueue(PrintJob(1, 5))
    jobs.enqueue(PrintJob(2, 7))
    jobs.enqueue(PrintJob(3, 13))

    # cycle until queue is empty
    tick = 0
    while not (jobs.is_empty() and p1.is_idle() and p2.is_idle()):
        tick += 1
        print("\n=== Tick {} ===".format(tick))
        p1.tick()
        p2.tick()

    print("\nAll done! Time for a pint...")

if __name__ == "__main__":
    main()

最后的结果是这样的

=== Tick 1 ===
Printer 1 got job 1
Printer 1 is printing...
Job 1: 4 / 5 pages remain
Printer 2 got job 2
Printer 2 is printing...
Job 2: 6 / 7 pages remain

=== Tick 2 ===
Printer 1 is printing...
Job 1: 3 / 5 pages remain
Printer 2 is printing...
Job 2: 5 / 7 pages remain

=== Tick 3 ===
Printer 1 is printing...
Job 1: 2 / 5 pages remain
Printer 2 is printing...
Job 2: 4 / 7 pages remain

=== Tick 4 ===
Printer 1 is printing...
Job 1: 1 / 5 pages remain
Printer 2 is printing...
Job 2: 3 / 7 pages remain

=== Tick 5 ===
Printer 1 is printing...
Job 1: 0 / 5 pages remain
Printer 1 finished job 1
Printer 2 is printing...
Job 2: 2 / 7 pages remain

=== Tick 6 ===
Printer 1 got job 3
Printer 1 is printing...
Job 3: 12 / 13 pages remain
Printer 2 is printing...
Job 2: 1 / 7 pages remain

=== Tick 7 ===
Printer 1 is printing...
Job 3: 11 / 13 pages remain
Printer 2 is printing...
Job 2: 0 / 7 pages remain
Printer 2 finished job 2

=== Tick 8 ===
Printer 1 is printing...
Job 3: 10 / 13 pages remain
Printer 2 is idle

=== Tick 9 ===
Printer 1 is printing...
Job 3: 9 / 13 pages remain
Printer 2 is idle

=== Tick 10 ===
Printer 1 is printing...
Job 3: 8 / 13 pages remain
Printer 2 is idle

=== Tick 11 ===
Printer 1 is printing...
Job 3: 7 / 13 pages remain
Printer 2 is idle

=== Tick 12 ===
Printer 1 is printing...
Job 3: 6 / 13 pages remain
Printer 2 is idle

=== Tick 13 ===
Printer 1 is printing...
Job 3: 5 / 13 pages remain
Printer 2 is idle

=== Tick 14 ===
Printer 1 is printing...
Job 3: 4 / 13 pages remain
Printer 2 is idle

=== Tick 15 ===
Printer 1 is printing...
Job 3: 3 / 13 pages remain
Printer 2 is idle

=== Tick 16 ===
Printer 1 is printing...
Job 3: 2 / 13 pages remain
Printer 2 is idle

=== Tick 17 ===
Printer 1 is printing...
Job 3: 1 / 13 pages remain
Printer 2 is idle

=== Tick 18 ===
Printer 1 is printing...
Job 3: 0 / 13 pages remain
Printer 1 finished job 3
Printer 2 is idle

All done! Time for a pint...

【讨论】:

  • 谢谢,非常棒的支持。
  • 我犯了一个错误。感谢您的帮助。
【解决方案2】:

这取决于。您将打印作业的优先级放在什么方面?完成打印作业所需的时间?队列中接收作业的顺序?

如果是后者,应该是这样的:

# printer is a class that contains a state 'idle' and a method 'print'

current_job = None
while ! job_queue.empty():
  if current_job != job_queue.peak(0)
    current_job = job_queue.pop(0)

  if printer1.idle():
    printer1.print_job(current_job)
  elif printer2.idle():
    printer2.print_job(current_job)
  else:
    # do nothing
    pass

  printer1.print()
  printer2.print()

在此基础上,您还可以在打印机类中拥有另一个名为“pages_todo”的状态变量,它是一个整数,告诉您当前打印机对象还剩多少页才能将其空闲状态更改为 true。

class Printer:
  def __init__(self):
    idle = false
    pages_todo = 0

  def print_job(pages):
    pages_todo += pages

  def print():
    pages_todo -= 1 if pages_todo > 0

【讨论】:

  • 打印机类中的“状态”是否已初始化?
  • 是的。对于所有已初始化的打印机,空闲类状态应该为真。除非您想在初始化打印机对象时打印测试页,否则它会以 idle = false 开始。
【解决方案3】:

我的解决方案使用 Queue 实现

class Queue:
    def __init__(self):
        self.items = []
        self.current_task = None

    def isEmpty(self):
        return self.items == []

    def enqueue(self, item):
        # ideally we should enqueue item by item
        self.items = item[1]
        self.current_task = item[0]

    def dequeue(self):
        return self.items.pop()

    def size(self):
        return len(self.items)

job1 = (1, list(range(5)))  # range serves as our list of pages
job2 = (2, list(range(7)))
job3 = (3, list(range(13)))

list_of_jobs = [job3, job2, job1]

# Two printers
printer1 = Queue()
printer2 = Queue()

for _ in range(6):
    if not printer1.isEmpty():
        printer1.dequeue()
    elif list_of_jobs:
        printer1.enqueue(list_of_jobs.pop())
        printer1.dequeue()

    if not printer2.isEmpty():
        printer2.dequeue()
    elif list_of_jobs:
        printer2.enqueue(list_of_jobs.pop())
        printer2.dequeue()

输出

print('printer 1 is working on {} page(s) and is on job {} while printer 2 is working on {} page(s) and is on job {}'.format(printer1.size(), printer1.current_task, printer2.size(), printer2.current_task))

【讨论】:

  • 谢谢,这帮助我理解了我的问题。
  • 我仍然会更新我的答案,它有一些小问题......但我很乐意提供帮助
  • 当我将循环数从 5 更改为代码中断?
  • 您有什么建议来确定每台打印机正在执行的作业。
  • 只需修改作业并使其成为元组,其中第一项是作业编号,第二项是要打印的页面列表
猜你喜欢
  • 2020-09-08
  • 2010-11-04
  • 2017-08-13
  • 2012-04-24
  • 2012-06-11
  • 1970-01-01
  • 2013-07-12
  • 1970-01-01
  • 2016-01-09
相关资源
最近更新 更多