Middle
Ի՞նչ է վարպետության աշխատանքը։
sobes.tech AI
Պատասխան AI-ից
Աշխատանքի գողություն (work stealing) մեխանիզմ է, որը հավասարակշռում է բեռը բազմատողային համակարգերում, որտեղ անգործ տողը (աշխատողը) "գողանում" է խնդիրներ մյուս, զբաղված տողից:
Հիմնական հատկանիշներ:
- Դեցենտրալիզացված: Յուրաքանչյուր տող կառավարում է իր տեղական խնդիրների հերթը:
- Ակտիվ: Անգործ տողը ակտիվորեն փնտրում է աշխատանք այլ տողերից:
- Բարձր արդյունավետություն: Էֆեկտիվ է անհավասար բեռների դեպքում:
Golango- ում օգտագործվում է պլանավորիչում (scheduler)՝ goroutin-ների բաշխման համար օպերացիոն համակարգի (M) տողերի միջև:
// Պսևդոկոդ, որը ցույց է տալիս աշխատանքային գողության կոնցեպցիան
package main
import "fmt"
import "sync"
import "time"
type Task struct {
id int
}
// Թղթային խնդիրների հերթ
type TaskQueue struct {
tasks []Task
mu sync.Mutex
}
func (q *TaskQueue) AddTask(task Task) {
q.mu.Lock()
defer q.mu.Unlock()
q.tasks = append(q.tasks, task)
}
func (q *TaskQueue) GetLocalTask() (Task, bool) {
q.mu.Lock()
defer q.mu.Unlock()
if len(q.tasks) == 0 {
return Task{}, false
}
task := q.tasks[0]
q.tasks = q.tasks[1:]
return task, true
}
// Փորձ է "գողանալ" խնդիր այլ տողից
func (q *TaskQueue) StealTask() (Task, bool) {
q.mu.Lock()
defer q.mu.Unlock()
if len(q.tasks) < 2 { // Չգողանում ենք, եթե խնդիրներ քիչ են
return Task{}, false
}
// Գողանում ենք միջինից կամ վերջից, որպեսզի չկլիշենք տեղական հանման հետ
index := len(q.tasks) / 2
task := q.tasks[index]
q.tasks = append(q.tasks[:index], q.tasks[index+1:]...)
return task, true
}
// Աշխատող թել
func worker(id int, localQueue *TaskQueue, otherQueues []*TaskQueue, wg *sync.WaitGroup) {
defer wg.Done()
for {
// Փորձում ենք վերցնել խնդիր տեղական հերթից
task, ok := localQueue.GetLocalTask()
if ok {
fmt.Printf("Աշխատող %d իրականացնում է խնդիր %d տեղական\n", id, task.id)
time.Sleep(100 * time.Millisecond) // Դիմացկունություն
continue
}
// Եթե տեղական հերթը դատարկ է, փորձում ենք գողանալ
stolen := false
for _, queue := range otherQueues {
if queue == localQueue {
continue // Չգողանում ենք իրանից
}
task, ok := queue.StealTask()
if ok {
fmt.Printf("Աշխատող %d գողացավ խնդիր %d\n", id, task.id)
time.Sleep(100 * time.Millisecond) // Դիմացկունություն
stolen = true
break // Հաջող գողություն, դուրս գալ
}
}
if !stolen {
// Եթե չի հաջողվել գողանալ, հնարավոր է, խնդիրներ այլևս չկան
// Իրական պլանավորիչում ավելի բարդ մեխանիզմներ կան
// Դեմո համար պարզապես դուրս ենք գալիս որոշ ժամանակ սպասելուց հետո
fmt.Printf("Աշխատող %d սպասում է...\n", id)
time.Sleep(50 * time.Millisecond)
// Իրական սցենարում այստեղ կլիներ ավարտման կամ լոկիացման մեխանիզմ
// return // Դեմո համար թույլ կտանք դուրս գալ
break // Պարզեցման համար
}
}
}
func main() {
numWorkers := 4
numTasks := 20
taskQueues := make([]*TaskQueue, numWorkers)
for i := range taskQueues {
taskQueues[i] = &TaskQueue{}
}
// Բաժանում ենք խնդիրները անհավասարապես գողության համար
for i := 0; i < numTasks; i++ {
queueIndex := i % 2 // Առաջին երկու աշխատողների համար ավել խնդիրներ
taskQueues[queueIndex].AddTask(Task{id: i})
}
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
// Տվեցինք բոլոր հերթերի հղումները, որպեսզի աշխատողը կարողանա "գողանալ"
otherQueues := make([]*TaskQueue, 0, numWorkers-1)
for j := range taskQueues {
if i != j {
otherQueues = append(otherQueues, taskQueues[j])
}
}
go worker(i, taskQueues[i], otherQueues, &wg)
}
wg.Wait()
fmt.Println("Բոլոր խնդիրները կատարվեցին")
}