Use python to draw SJF schedule

First published in csdn. Original.
https://blog.csdn.net/weixin_43906799/article/details/105510046

SJF algorithm:

The shortest job first (SJF) scheduling algorithm correlates each process with the length of its next CPU execution. In fact, short processes / jobs (requiring the shortest service time) account for a large proportion in the actual situation. In order to make them execute preferentially, the least average waiting time, average turnaround time, and average weighted turnaround time are pursued. Short job priority may result in long job not being processed)

Overall concept

The idea of ​​drawing with python came from the time when writing a schedule graph job. At that time, I thought about drawing with python. There are two ideas to dynamically draw a scheduling diagram, and there is the method used now. Why use class to write this job, one is that the next job can directly inherit the SJF class, and then modify the scheduling function and sort function. The second is to use class to write code to solve a type of problem, the code looks pretty.

Algorithm design structure diagram

imgClick and drag to move

Program execution result graph

imgClick and drag to move

Job information

Job name Time of arrival operation hours
A 0 5
B 1 4
C 2 1
D 4 2
E 5 1

The basic idea

(1) Class initialization:

For the class of process scheduling SJF algorithm, first of all we need to have member variables, that is, the member variables that are roughly needed. Basically, so much is needed.

self.data = [] Stored process
self.name = '' Process name
self.service_time = 0 service hours
self.arrival_time = 0 Time of arrival
self.state = '' Initial state
self.number = 0 Number of processes
self.timeout = 0 Timeout limit
self.start = 0 Starting time
self.end = 0 End Time
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

Click and drag to move

(2) Obtain data:

The acquired data can be read from a file (such as .txt) or from the console. One place required here is the data format, name, arrival time, and service time. Separated by spaces. As shown in the table below:

name arrival_time service_time
A 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

Click and drag to move

(3) Schedule:

That is, design algorithms to achieve SJF. The basic algorithm idea is to maintain a priority queue. As shown:

img

Click and drag to move

Every time when scheduling, according to the need, then update the information, change the status of the job and the time of arrival and end. To obtain the next job or multiple jobs at the same time, a situation needs to be considered here, that is, the current time slice cannot obtain the next job, and it needs to wait for a period of time for the job to arrive before it can be executed. This situation is particularly critical. Then perform sorting and maintain this priority queue.

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'])

Click and drag to move

(4) Sorting and information update:

The implementation of sorting is actually very simple. The previous structure diagram has also shown that there are two sorting methods for the SJF algorithm, which are used in different processes. Data update is to update the original data, including the calculation status, start time, end time, turnaround time, average turnaround time and so on.

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])

Click and drag to move

(5) Data output:

Why data output, in fact, this is a method of data visualization. That is to express all kinds of information intuitively. So the data output part is to set your own layout and layout, you can use the \ t tab to play the table.

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']))

Click and drag to move

(6) PLT generated scheduling diagram display:

Use the third-party library of Python to draw according to the data, and then display beautiful pictures.

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])

Click and drag to move

imgClick and drag to move

imgClick and drag to move

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')

Click and drag to move

imgClick and drag to moveimgClick and drag to move

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='-.')  # 网格

Click and drag to move

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

Click and drag to move

Program execution process:

Support two input methods, manual input and data import.

data import:

imgClick and drag to move

Raw data

imgClick and drag to move

Before scheduling:

imgClick and drag to move

In scheduling:

imgClick and drag to move

After scheduling:

imgClick and drag to move

Generate scheduling diagram:

imgClick and drag to move

Enter data manually:

imgClick and drag to move

imgClick and drag to move

Before scheduling

imgClick and drag to move Scheduling

imgClick and drag to move

After scheduling

imgClick and drag to move

Generate scheduling diagram:

imgClick and drag to move

Program source code:

# -*- 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')

Guess you like

Origin www.cnblogs.com/wfy-beliefs/p/12724544.html