📜  门| GATE CS 2020 |问题19(1)

📅  最后修改于: 2023-12-03 15:28:38.656000             🧑  作者: Mango

门 | GATE CS 2020 | 问题19

本题是一道操作系统概念题,需要涉及进程调度、同步以及进程通信等知识点。

题目描述

一台计算机有 $N$ 个进程,$P_1, P_2, ..., P_N$,每个进程都有一个固定的优先级 $P_{priority}$,值为 $0, 1, ..., N-1$,所有进程在 CPU 中轮流执行,每个进程的 CPU 时间片为 $2$。假设进程在执行时不会被打断,即不会发生中断。现有如下两个问题需要解决:

  1. 最小化平均等待时间(waiting time)
  2. 最大化系统吞吐率(system throughput)

其中等待时间是指一个进程从进入就绪队列到开始执行的时间。

解题思路
题目分析

考虑这样一个场景:假设有两个进程 $P_1$ 和 $P_2$,它们的优先级分别为 $0$ 和 $1$,它们将交替执行,按顺序分别为 $P_1 \rightarrow P_2 \rightarrow P_1 \rightarrow P_2 \rightarrow \cdots$,每个进程的 CPU 时间片为 $2$。那么,每个进程被分配为 $2$ 个时间片。假设每个进程在进入就绪队列时都已经运行了一定时间,可以得到它们的等待时间为 $0, 2$,平均等待时间为 $\frac{0+2}{2}=1$。此时系统的吞吐率为 $\frac{2}{4}=0.5$。

接下来考虑如何最小化平均等待时间和最大化系统吞吐率。

小问题:最小化平均等待时间

最小化平均等待时间的核心思想是优先级高的进程优先执行。这里需要采用优先级调度算法,选择一个进程中优先级最高的进程,执行 $2$ 个时间片。

假设当前有 $n$ 个进程在就绪队列中,那么可以得到进程的平均等待时间为

$$\frac{0\times N_0 + 2\times N_1 + \cdots + (n-1)\times N_{n-1}}{n}$$

其中,$N_i$ 表示优先级为 $i$ 的进程在就绪队列中的数量。为了最小化平均等待时间,需要找到一种方法,使得每个优先级的进程在就绪队列中的等待时间相同。这可以通过循环执行进程来实现。

具体来说,可以维护 $N$ 个队列 $Q_0, Q_1, ..., Q_{N-1}$,其中第 $i$ 个队列保存所有优先级为 $i$ 的进程。每个队列中的进程都按照先来先服务(first-come first-served,FCFS)的方式进行调度。每次选择一个队列,并从队列中选择一个进程执行 $2$ 个时间片。如果当前队列为空,则直接跳过该队列。

由于每个优先级的进程都得到了相同的等待时间,所以不需要在执行过程中计算等待时间。此时进程的平均等待时间为

$$\frac{0 + 0 + \cdots + 0}{N}=0$$

因此,这种方法可以最小化平均等待时间。

大问题:最大化系统吞吐率

最大化系统吞吐率的核心思想是尽可能多地执行进程。这里需要采用时间片轮转(time slice round-robin,TSRR)算法,每个进程都可以获得一部分 CPU 时间,从而尽可能多地执行进程。

假设每个进程的 CPU 时间段为 $T_1, T_2, ..., T_N$,其中 $T_i$ 表示第 $i$ 个进程获得 CPU 时间的总量。为了最大化系统吞吐率,每个进程都需要获得相等的 CPU 时间。

具体来说,假设每个进程的 CPU 时间片为 $q$,则每个进程可以获得 $\min(T_i, q)$ 的 CPU 时间。如果进程在所获得的时间片中没有完成执行,则将其加入就绪队列尾部,并等待下一次调度。

这种方法可以保证每个进程都能获得相等的 CPU 时间,因此可以最大化系统吞吐率。此时系统吞吐率为

$$\frac{\sum_{i=1}^N \lfloor\frac{T_i}{q}\rfloor}{\sum_{i=1}^N \lfloor\frac{T_i}{q}\rfloor + \sum_{i=1}^N (T_i \mod q)}$$

参考代码

下面是参考代码,其中 process 为进程类,fcfs 函数为最小化平均等待时间的实现,tsrr 函数为最大化系统吞吐率的实现。

class Process:
    def __init__(self, priority, time):
        self.priority = priority
        self.time = time  # 进程需要的总时间

def fcfs(processes):
    N = len(processes)
    queue = [[] for _ in range(N)]  # 优先级队列

    for p in processes:
        queue[p.priority].append(p)

    time = 0  # 当前时间
    waiting_time = [0] * N  # 等待时间

    while sum(map(len, queue)) > 0:
        for q in queue:
            if len(q) == 0:
                continue
            p = q.pop(0)
            waiting_time[p.priority] += time
            time += 2

        # 将队列重新排列,确保优先级高的进程优先执行
        queue = [q for q in queue if len(q) > 0] + [[] for _ in range(N)]

    average_waiting_time = sum(waiting_time) / N
    return average_waiting_time

def tsrr(processes, q):
    N = len(processes)
    queue = processes[:]  # 就绪队列

    time = 0  # 当前时间
    waiting_time = [0] * N  # 等待时间

    while len(queue) > 0:
        p = queue.pop(0)
        t = min(p.time, q)
        p.time -= t

        # 计算等待时间
        waiting_time[p.priority] += time
        time += t

        if p.time > 0:
            queue.append(p)
        else:
            # 进程已经执行完毕
            pass

    average_waiting_time = sum(waiting_time) / N
    throughput = sum([p.time_old for p in processes]) / time
    return throughput