diff --git a/homeworks/12_goroutines_and_scheduler/README.md b/homeworks/12_goroutines_and_scheduler/README.md new file mode 100644 index 0000000..aa903ba --- /dev/null +++ b/homeworks/12_goroutines_and_scheduler/README.md @@ -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 (если у одного из планировщиков закончатся задачи, их нужно будет украсть у другого). \ No newline at end of file diff --git a/homeworks/12_goroutines_and_scheduler/binary_heap.go b/homeworks/12_goroutines_and_scheduler/binary_heap.go new file mode 100644 index 0000000..1ce6ed9 --- /dev/null +++ b/homeworks/12_goroutines_and_scheduler/binary_heap.go @@ -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 + } +} diff --git a/homeworks/12_goroutines_and_scheduler/homework.go b/homeworks/12_goroutines_and_scheduler/homework.go new file mode 100644 index 0000000..1a3bd82 --- /dev/null +++ b/homeworks/12_goroutines_and_scheduler/homework.go @@ -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) +} diff --git a/homeworks/12_goroutines_and_scheduler/homework_test.go b/homeworks/12_goroutines_and_scheduler/homework_test.go new file mode 100644 index 0000000..12c775f --- /dev/null +++ b/homeworks/12_goroutines_and_scheduler/homework_test.go @@ -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) +}