Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions homeworks/12_goroutines_and_scheduler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Домашнее задание №12

В домашнем задании нужно реализовать алгоритм приоритетного планирования задач.

Для алгоритма приоритетного планирования нужно будет реализовать сущность планировщика. Особенность реализации будет заключаться в том, что приоритет у задач можно будет менять после того, как они уже были запланированы в планирощике. Для реализации приоритетного планирования вам могут помочь двоичные кучи, поподробнее с ними можно ознакомиться [здесь](https://habr.com/ru/articles/112222/).

API для планировщика будет выглядеть следующим образом:
```go
type Task struct {
Identifier int
Priority int
}

type Scheduler struct { ... }

func NewScheduler() Scheduler // создать планировщик
func (s *Scheduler) AddTask(task Task) // запланировать задачу
func (s *Scheduler) ChangeTaskPriority(taskID int, newPriority int) // изменить приоритет задачи по идентификатору
func (s *Scheduler) GetTask() Task // получить задачу с наибольшим приоритетом для исполнения
```

Для выполнения домашнего задания подготовлен шаблон кода и основные тесты, которую помогут проверить корректность реализации конвертации. Шаблона доступен по [ссылке](https://github.com/Balun-courses/deep_go/blob/master/homework/goroutines_and_scheduler/homework_test.go).

Задание со звездочкой
Выполнять необязательно, но если вы хотите, можете попробовать реализовать шардирование планировщика вместе с реализацией концепции Work Sharing (если у одного из планировщиков закончатся задачи, их нужно будет украсть у другого).
90 changes: 90 additions & 0 deletions homeworks/12_goroutines_and_scheduler/binary_heap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package homework12

import "errors"

var ErrNotFound = errors.New("not found")

type Prioritisable interface {
GetIdentifier() int
GetPriority() int
}

type BinaryHeap struct {
list []Prioritisable
}

func NewBinaryHeap() BinaryHeap {
return BinaryHeap{
list: make([]Prioritisable, 0),
}
}

func (bh *BinaryHeap) Size() int {
return len(bh.list)
}

func (bh *BinaryHeap) Add(elem Prioritisable) {
bh.list = append(bh.list, elem)

i := bh.Size() - 1
parent := (i - 1) / 2

for bh.list[parent].GetPriority() < bh.list[i].GetPriority() {
bh.list[i], bh.list[parent] = bh.list[parent], bh.list[i]
i = parent
parent = (i - 1) / 2
}
}

func (bh *BinaryHeap) GetMax() (result Prioritisable, err error) {
if bh.Size() == 0 {
return nil, ErrNotFound
}

result = bh.list[0]

bh.list[0], bh.list[bh.Size()-1] = bh.list[bh.Size()-1], bh.list[0]
bh.list = bh.list[0 : bh.Size()-1]
bh.hapify(0)

return result, nil
}

func (bh *BinaryHeap) Get(identifier int) (result Prioritisable, err error) {
for i, v := range bh.list {
if v.GetIdentifier() == identifier {
result = bh.list[i]
bh.list[i], bh.list[bh.Size()-1] = bh.list[bh.Size()-1], bh.list[i]
bh.list = bh.list[:bh.Size()-1]
bh.hapify(i)
return result, nil
}
}
return nil, ErrNotFound
}

func (bh *BinaryHeap) hapify(i int) {
if i < 0 {
return
}

var leftChildIdx, rightChildIdx, LargestChildIdx int

for {
leftChildIdx = 2*i + 1
rightChildIdx = 2*i + 2
LargestChildIdx = i

if leftChildIdx < bh.Size() && bh.list[leftChildIdx].GetPriority() > bh.list[LargestChildIdx].GetPriority() {
LargestChildIdx = leftChildIdx
}
if rightChildIdx < bh.Size() && bh.list[rightChildIdx].GetPriority() > bh.list[LargestChildIdx].GetPriority() {
LargestChildIdx = rightChildIdx
}
if LargestChildIdx == i {
return
}
bh.list[LargestChildIdx], bh.list[i] = bh.list[i], bh.list[LargestChildIdx]
i = LargestChildIdx
}
}
60 changes: 60 additions & 0 deletions homeworks/12_goroutines_and_scheduler/homework.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package homework12

import (
"fmt"
)

type Task struct {
identifier int
priority int
}

func (t *Task) GetIdentifier() int {
return t.identifier
}

func (t *Task) GetPriority() int {
return t.priority
}

func (t *Task) SetIdentifier(val int) {
t.identifier = val
}

func (t *Task) SetPriority(val int) {
t.priority = val
}

type Scheduler struct {
BinaryHeap
}

func NewScheduler() Scheduler {
return Scheduler{
BinaryHeap: NewBinaryHeap(),
}
}

func (s *Scheduler) AddTask(task *Task) {
s.Add(task)
}

func (s *Scheduler) ChangeTaskPriority(taskID int, newPriority int) {
task, err := s.Get(taskID)
if err != nil {
fmt.Println(err.Error())
return
}
newTask := task.(*Task)
newTask.SetPriority(newPriority)
s.Add(newTask)
}

func (s *Scheduler) GetTask() *Task {
task, err := s.GetMax()
if err != nil {
fmt.Println(err.Error())
return &Task{}
}
return task.(*Task)
}
42 changes: 42 additions & 0 deletions homeworks/12_goroutines_and_scheduler/homework_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package homework12

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestTrace(t *testing.T) {
task1 := &Task{identifier: 1, priority: 10}
task2 := &Task{identifier: 2, priority: 20}
task3 := &Task{identifier: 3, priority: 30}
task4 := &Task{identifier: 4, priority: 40}
task5 := &Task{identifier: 5, priority: 50}
taskNil := &Task{}

scheduler := NewScheduler()

task := scheduler.GetTask()
assert.Equal(t, taskNil, task)

scheduler.AddTask(task1)
scheduler.AddTask(task2)
scheduler.AddTask(task3)
scheduler.AddTask(task4)
scheduler.AddTask(task5)

task = scheduler.GetTask()
assert.Equal(t, task5, task)

task = scheduler.GetTask()
assert.Equal(t, task4, task)

scheduler.ChangeTaskPriority(1, 100)

task = scheduler.GetTask()
assert.Equal(t, task1, task)

task = scheduler.GetTask()

assert.Equal(t, task3, task)
}