Pythonを使用してSJFスケジュールを描画する

csdnで最初に公開されました。オリジナル。
https://blog.csdn.net/weixin_43906799/article/details/105510046

SJFアルゴリズム:

最短ジョブ優先(SJF)スケジューリングアルゴリズムは、各プロセスを次のCPU実行の長さと関連付けます。実際には、短いプロセス/ジョブ(最短のサービス時間を必要とする)が実際の状況で大きな割合を占めています。それらを優先的に実行させるために、最小の平均待機時間、平均ターンアラウンド時間、および平均加重ターンアラウンド時間が追跡されます。短いジョブの優先順位により、長いジョブが処理されない場合があります)

全体的なコンセプト

Pythonで描画するというアイデアは、スケジュールグラフジョブを作成したときから生まれました。当時はPythonで描くことを考えていましたが、動的にスケジューリング図を描くには2つのアイデアがあり、現在使われている方法があります。クラスを使用してこのジョブを作成する理由の1つは、次のジョブがSJFクラスを直接継承し、スケジューリング関数とソート関数を変更できることです。2つ目は、クラスを使用してコードを記述し、ある種の問題を解決することです。コードはきれいに見えます。

アルゴリズム設計構造図

imgクリックしてドラッグして移動します

プログラム実行結果グラフ

imgクリックしてドラッグして移動します

求人情報

ジョブ名 到着時間 実行時間
0 5
B 1 4
C 2 1
D 4 2
E 5 1

基本的な考え方

(1)クラスの初期化:

プロセススケジューリングSJFアルゴリズムのクラスでは、最初に、メンバー変数、つまり大まかに必要とされるメンバー変数が必要です。基本的に、それだけが必要です。

self.data = [] ストアドプロセス
self.name = '' プロセス名
self.service_time = 0 サービス時間
self.arrival_time = 0 到着時間
self.state = '' 初期状態
自己番号= 0 プロセスの数
self.timeout = 0 タイムアウト制限
self.start = 0 開始時間
self.end = 0 終了時間
def __init__(self):
        super(Solution, self).__init__()
        # save tasks
        self.data = []
        self.name = ''
        self.service_time = 0
        self.arrival_time = 0
        self.state = ''
        self.number = 0
        self.timeout = 0
        self.start = 0
        self.end = 0

クリックしてドラッグして移動します

(2)データを取得します。

取得したデータは、ファイル(.txtなど)またはコンソールから読み取ることができます。ここで必要な1つの場所は、データ形式、名前、到着時間、およびサービス時間です。スペースで区切ります。次の表に示すように:

名前 到着時刻 service_time
0 5
B 1 4
C 2 1
D 4 2
E 5 1
def get_data_file(self):
        with open('data.txt', "r", encoding="utf-8") as file:
            for line in file.read().splitlines():
                name, arrival_time, service_time = line.split()
                # insert the task
                self.insert_data(name, arrival_time, service_time)
        file.close()
        # initial queue
        # sort first arrival_time and second service_time
        self.data.sort(key=lambda x: (x['arrival_time'], x['service_time']))
        # update and recode id
        for i in range(self.number):
            self.data[i]['index'] = i

def get_data_input(self):
        print('How many tasks do you want input?')
        tasks_number = int(input('Please enter an integer of type int:'))
        print('Please enter name and arrival_time and service_time of task')
        print('such as:A 0 5')
        for _ in range(tasks_number):
            name, arrival_time, service_time = input('Please enter\n').split()
            self.insert_data(name, arrival_time, service_time)
        # initial queue
        # sort first arrival_time and second service_time
        self.data.sort(key=lambda x: (x['arrival_time'], x['service_time']))
        # update and recode id
        for i in range(self.number):
            self.data[i]['index'] = i

クリックしてドラッグして移動します

(3)スケジュール:

つまり、SJFを実現するアルゴリズムを設計します。基本的なアルゴリズムの考え方は、優先キューを維持することです。示されているように:

img

クリックしてドラッグして移動します

スケジュールするたびに、必要に応じて、情報を更新し、ジョブのステータスと到着時刻と終了時刻を変更します。次のジョブまたは複数のジョブを同時に取得するには、ここで状況を考慮する必要があります。つまり、現在のタイムスライスが次のジョブを取得できず、ジョブが到着するまでしばらく待機する必要があります。この状況は特に重要です。次に、ソートを実行し、この優先キューを維持します。

def implement(self):
        '''start algorithm'''
        # get first task
        data = [self.data[0]]
        # update the time of start
        self.start = self.end = data[0]['arrival_time']
        while data:
            # update information
            self.update_information(
                data[0]['index'], self.end, self.end + data[0]['service_time'])
            # get next task or tasks
            data += self.get_next_data(data.pop(0)['index'], data)
            # maintain the queue
            data = self.sort_data(data)
        self.data.sort(key=lambda x: x['id'])

クリックしてドラッグして移動します

(4)並べ替えと情報の更新:

前の構造図では、SJFアルゴリズムには2つのソート方法があり、異なるプロセスで使用されていることも示しています。データ更新とは、計算ステータス、開始時間、終了時間、所要時間、平均所要時間などを含む元のデータを更新することです。

def update_information(self, index, start, end):
        self.data[index]['start'] = start
        self.data[index]['end'] = end
        self.data[index]['state'] = 'f'
        self.data[index]['turnaround_time'] = end - \
            self.data[index]['arrival_time']
        self.data[index]['authorized_turnover_time'] = self.data[index]['turnaround_time'] / \
            self.data[index]['service_time']
        self.start = start
        self.end = end
        self.show_data_running(start, end, self.data[index])

クリックしてドラッグして移動します

(5)データ出力:

なぜデータ出力なのか、実際、これはデータ視覚化の方法です。それはあらゆる種類の情報を直感的に表現することです。したがって、データ出力部分は独自のレイアウトとレイアウトを設定することであり、\ tタブを使用してテーブルを再生できます。

def show_data(self):
        print("{:<6}{:<10}{:<10}{:<10}{:<6}{:<8}{:<7}{:<6}".format(
            'name', 'arr_time', 'ser_time', 'state', '周转时间', '带权周转时间', 'start', 'end'))
        for task in sorted(self.data, key=lambda x: x['id']):
            print("{:<6}{:<10}{:<10}{:<10}{:<10}{:<14.2f}{:<7}{:<4}".format(
                task['name'],
                task['arrival_time'],
                task['service_time'],
                task['state'],
                task['turnaround_time'],
                task['authorized_turnover_time'],
                task['start'],
                task['end']))

クリックしてドラッグして移動します

(6)PLTで生成されたスケジューリング図の表示:

Pythonのサードパーティライブラリを使用して、データに従って描画し、美しい画像を表示します。

def init_image(self):
        # size = 1000 * 500
        plt.figure('SJF', figsize=(10, 5))
        self.drow_image()
        # setting xticks for 0 to self.end + 2
        plt.xticks([i for i in range(self.end + 3)])
        # setting title
        plt.title('the time of task about SJF')

        plt.xlabel('')
        plt.ylabel('tasks')
        # setting yticks.such as A == 0
        plt.yticks(self.get_y_ticks()[0], self.get_y_ticks()[1])

クリックしてドラッグして移動します

imgクリックしてドラッグして移動します

imgクリックしてドラッグして移動します

def drow_image(self):
        for task in self.data:
            # the time line of task from start to end
            plt.plot([task['start'], task['end']],
                     [task['id'], task['id']],
                     label=task['name'],
                     lw=2)
            # annotation of the key point
            plt.plot([task['end'], task['end']],
                     [-1, task['id']],
                     'k--',
                     lw=1)
        # legend
        plt.legend(loc='best')

クリックしてドラッグして移動します

imgクリックしてドラッグして移動しますimgクリックしてドラッグして移動します

def set_ax(self):
        ax = plt.gca()  # 获取到当前坐标轴信息
        ax.spines['right'].set_color('none')
        ax.spines['bottom'].set_color('none')
        ax.xaxis.set_ticks_position('top')   # 将X坐标轴移到上面
        ax.invert_yaxis()  # 反转Y坐标轴
        ax.grid(True, linestyle='-.')  # 网格

クリックしてドラッグして移動します

def show_image(self):
        self.init_image()
        self.set_ax()
        plt.savefig('SJF.png', dpi=300)
        plt.show()

クリックしてドラッグして移動します

プログラム実行プロセス:

手動入力とデータインポートの2つの入力方法をサポートします。

データのインポート:

imgクリックしてドラッグして移動します

生データ

imgクリックしてドラッグして移動します

スケジュールする前に:

imgクリックしてドラッグして移動します

スケジューリング:

imgクリックしてドラッグして移動します

スケジュール後:

imgクリックしてドラッグして移動します

スケジューリング図を生成します。

imgクリックしてドラッグして移動します

データを手動で入力します。

imgクリックしてドラッグして移動します

imgクリックしてドラッグして移動します

スケジュールする前に

imgクリックしてドラッグして移動します スケジューリング

imgクリックしてドラッグして移動します

スケジュール後

imgクリックしてドラッグして移動します

スケジューリング図を生成します。

imgクリックしてドラッグして移動します

プログラムのソースコード:

# -*- coding: utf-8 -*-
# @Author: wfy
# @Date:   2020-04-10 15:31:44
# @Last Modified by:   wfy
# @Last Modified time: 2020-04-14 13:46:31
import matplotlib.pyplot as plt


class Solution():
    """to achieve SJF"""

    def __init__(self):
        super(Solution, self).__init__()
        # save tasks
        self.data = []
        self.name = ''
        self.service_time = 0
        self.arrival_time = 0
        self.state = ''
        self.number = 0
        self.timeout = 0
        self.start = 0
        self.end = 0

    def insert_data(self, name, arrival_time, service_time):
        self.data.append({
            'id': self.number,
            'name': name,
            'arrival_time': int(arrival_time),
            'service_time': int(service_time),
            'state': 'w',
            'turnaround_time': 0,
            'authorized_turnover_time': 0,
            'start': 0,
            'end': 0
        })
        self.timeout = max(self.timeout, int(arrival_time))
        self.number += 1

    def get_data_file(self):
        with open('data.txt', "r", encoding="utf-8") as file:
            for line in file.read().splitlines():
                name, arrival_time, service_time = line.split()
                # insert the task
                self.insert_data(name, arrival_time, service_time)
        file.close()
        # initial queue
        # sort first arrival_time and second service_time
        self.data.sort(key=lambda x: (x['arrival_time'], x['service_time']))
        # update and recode id
        for i in range(self.number):
            self.data[i]['index'] = i

    def get_data_input(self):
        print('How many tasks do you want input?')
        tasks_number = int(input('Please enter an integer of type int:'))
        print('Please enter name and arrival_time and service_time of task')
        print('such as:A 0 5')
        for _ in range(tasks_number):
            name, arrival_time, service_time = input('Please enter\n').split()
            self.insert_data(name, arrival_time, service_time)
        # initial queue
        # sort first arrival_time and second service_time
        self.data.sort(key=lambda x: (x['arrival_time'], x['service_time']))
        # update and recode id
        for i in range(self.number):
            self.data[i]['index'] = i

    def show_data_running(self, start, end, data):
        print('-'*40)
        print("from {:} to {:}".format(start, end))
        print("task name:{:}".format(data['name']))
        print("task state:{:}\n".format('R'))

    def show_data(self):
        print("{:<6}{:<10}{:<10}{:<10}{:<6}{:<8}{:<7}{:<6}".format(
            'name', 'arr_time', 'ser_time', 'state', '周转时间', '带权周转时间', 'start', 'end'))
        for task in sorted(self.data, key=lambda x: x['id']):
            print("{:<6}{:<10}{:<10}{:<10}{:<10}{:<14.2f}{:<7}{:<4}".format(
                task['name'],
                task['arrival_time'],
                task['service_time'],
                task['state'],
                task['turnaround_time'],
                task['authorized_turnover_time'],
                task['start'],
                task['end']))

    def cmp(self):
        '''the method of sort'''
        return lambda x: (x['service_time'], x['arrival_time'], x['index'])

    def sort_data(self, data):
        return sorted(data, key=self.cmp())

    def update_information(self, index, start, end):
        self.data[index]['start'] = start
        self.data[index]['end'] = end
        self.data[index]['state'] = 'f'
        self.data[index]['turnaround_time'] = end - \
            self.data[index]['arrival_time']
        self.data[index]['authorized_turnover_time'] = self.data[index]['turnaround_time'] / \
            self.data[index]['service_time']
        self.start = start
        self.end = end
        self.show_data_running(start, end, self.data[index])

    def get_next_data(self, index,  data):
        # get tasks from the beginning to the end of the current task
        result = [x for x in self.data if x['arrival_time'] <=
                  self.end and x['state'] == 'w' and x not in data]
        if result or data:
            return result
        # no tasks entered at current time
        for task in self.data:
            if task['state'] == 'w':
                self.start = self.end = task['arrival_time']
                return [task]
        return []

    def implement(self):
        '''start algorithm'''
        # get first task
        data = [self.data[0]]
        # update the time of start
        self.start = self.end = data[0]['arrival_time']
        while data:
            # update information
            self.update_information(
                data[0]['index'], self.end, self.end + data[0]['service_time'])
            # get next task or tasks
            data += self.get_next_data(data.pop(0)['index'], data)
            # maintain the queue
            data = self.sort_data(data)
        self.data.sort(key=lambda x: x['id'])

    def get_y_ticks(self):
        return [x['id'] for x in self.data] + [self.data[-1]['id'] + 1], [x['name'] for x in self.data] + ['']

    def init_image(self):
        # size = 1000 * 500
        plt.figure('SJF', figsize=(10, 5))
        self.drow_image()
        # setting xticks for 0 to self.end + 2
        plt.xticks([i for i in range(self.end + 3)])
        # setting title
        plt.title('the time of task about SJF')

        plt.xlabel('')
        plt.ylabel('tasks')
        # setting yticks.such as A == 0
        plt.yticks(self.get_y_ticks()[0], self.get_y_ticks()[1])

    def drow_image(self):
        for task in self.data:
            # the time line of task from start to end
            plt.plot([task['start'], task['end']],
                     [task['id'], task['id']],
                     label=task['name'],
                     lw=2)
            # annotation of the key point
            plt.plot([task['end'], task['end']],
                     [-1, task['id']],
                     'k--',
                     lw=1)
        # legend
        plt.legend(loc='best')

    def set_ax(self):
        ax = plt.gca()  # 获取到当前坐标轴信息
        ax.spines['right'].set_color('none')
        ax.spines['bottom'].set_color('none')
        ax.xaxis.set_ticks_position('top')   # 将X坐标轴移到上面
        ax.invert_yaxis()  # 反转Y坐标轴
        ax.grid(True, linestyle='-.')  # 网格

    def show_image(self):
        self.init_image()
        self.set_ax()
        plt.savefig('SJF.png', dpi=300)
        plt.show()

    def main(self):
        if input('Do you want get data by file? y/Y or n/N\n') in ['y', 'Y']:
            SJF.get_data_file()
        else:
            SJF.get_data_input()
        SJF.show_data()
        SJF.implement()
        SJF.show_data()
        SJF.show_image()


if __name__ == '__main__':
    try:
        SJF = Solution()
        SJF.main()
    except Exception as e:
        print('An exception', e)
    else:
        print('Finish')
    finally:
        print('finally')

おすすめ

転載: www.cnblogs.com/wfy-beliefs/p/12724544.html