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
Program execution result graph
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
(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
(3) Schedule:
That is, design algorithms to achieve SJF. The basic algorithm idea is to maintain a priority queue. As shown:
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'])
(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])
(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']))
(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])
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()
Program execution process:
Support two input methods, manual input and data import.
data import:
Raw data
Before scheduling:
In scheduling:
After scheduling:
Generate scheduling diagram:
Enter data manually:
Before scheduling
Scheduling
After scheduling
Generate scheduling diagram:
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')