From 5d120edcd7b2fd74851be337a9143befabcb4699 Mon Sep 17 00:00:00 2001 From: Vladislav Byrgazov Date: Sun, 11 Jan 2026 21:28:46 +0500 Subject: [PATCH 1/2] homework: implement binary heap Signed-off-by: Vladislav Byrgazov --- .../12_goroutines_and_scheduler/README.md | 25 +++++ .../binary_heap.go | 90 +++++++++++++++++ .../homework_test.go | 98 +++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 homeworks/12_goroutines_and_scheduler/README.md create mode 100644 homeworks/12_goroutines_and_scheduler/binary_heap.go create mode 100644 homeworks/12_goroutines_and_scheduler/homework_test.go 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..a39f429 --- /dev/null +++ b/homeworks/12_goroutines_and_scheduler/binary_heap.go @@ -0,0 +1,90 @@ +package main + +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_test.go b/homeworks/12_goroutines_and_scheduler/homework_test.go new file mode 100644 index 0000000..339ac46 --- /dev/null +++ b/homeworks/12_goroutines_and_scheduler/homework_test.go @@ -0,0 +1,98 @@ +package main + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +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) +} + +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) +} From 31a94440c4df646cf3e5bc3feb571719b10e9e73 Mon Sep 17 00:00:00 2001 From: Vladislav Byrgazov Date: Sun, 11 Jan 2026 21:39:13 +0500 Subject: [PATCH 2/2] fix: fix linter and file structure Signed-off-by: Vladislav Byrgazov --- .../binary_heap.go | 4 +- .../12_goroutines_and_scheduler/homework.go | 60 +++++++++++++++++++ .../homework_test.go | 58 +----------------- 3 files changed, 63 insertions(+), 59 deletions(-) create mode 100644 homeworks/12_goroutines_and_scheduler/homework.go diff --git a/homeworks/12_goroutines_and_scheduler/binary_heap.go b/homeworks/12_goroutines_and_scheduler/binary_heap.go index a39f429..1ce6ed9 100644 --- a/homeworks/12_goroutines_and_scheduler/binary_heap.go +++ b/homeworks/12_goroutines_and_scheduler/binary_heap.go @@ -1,8 +1,8 @@ -package main +package homework12 import "errors" -var ErrNotFound = errors.New("Not found") +var ErrNotFound = errors.New("not found") type Prioritisable interface { GetIdentifier() int 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 index 339ac46..12c775f 100644 --- a/homeworks/12_goroutines_and_scheduler/homework_test.go +++ b/homeworks/12_goroutines_and_scheduler/homework_test.go @@ -1,67 +1,11 @@ -package main +package homework12 import ( - "fmt" "testing" "github.com/stretchr/testify/assert" ) -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) -} - func TestTrace(t *testing.T) { task1 := &Task{identifier: 1, priority: 10} task2 := &Task{identifier: 2, priority: 20}