Middle
Kas ir workshopping?
sobes.tech AI
Atbilde no AI
Darba zagšana (work stealing) ir mehānisms slodzes līdzsvarošanai daudzšūnu sistēmās, kur neaktīvs pavediens (darbinieks) "zog" uzdevumus no cita, aizņemta pavediena rinda.
Galvenās īpašības:
- Dezentralizēts: Katrs pavediens pārvalda savu vietējo uzdevumu rindu.
- Aktīvs: Neaktīvs pavediens aktīvi meklē darbu citos.
- Augsta veiktspēja: Efektīvs nevienmērīgas slodzes gadījumā.
Golang tiek izmantots plānotājā (scheduler) goroutine-ļu sadalīšanai starp operētājsistēmas pavedieniem (M). Kad viens M pabeidz savu pašreizējo darbu (goroutine kopu P-de), tas meklē goroutine-ļ citos P caur to vietējām rindām.
// Pseido-kods, kas demonstrē darba zagšanas koncepciju
package main
import "fmt"
import "sync"
import "time"
type Task struct {
id int
}
// Uzdevumu rinda
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
}
// Mēģinājums "zagt" uzdevumu no citas rindas
func (q *TaskQueue) StealTask() (Task, bool) {
q.mu.Lock()
defer q.mu.Unlock()
if len(q.tasks) < 2 { // Nezog, ja ir maz uzdevumu
return Task{}, false
}
// Zog no vidus vai beigām, lai izvairītos no konfliktiem ar vietējo izņemšanu
index := len(q.tasks) / 2
task := q.tasks[index]
q.tasks = append(q.tasks[:index], q.tasks[index+1:]...)
return task, true
}
// Darba pavediena funkcija
func worker(id int, localQueue *TaskQueue, otherQueues []*TaskQueue, wg *sync.WaitGroup) {
defer wg.Done()
for {
// Mēģinājums ņemt uzdevumu no vietējās rindas
task, ok := localQueue.GetLocalTask()
if ok {
fmt.Printf("Darbinieks %d veic uzdevumu %d vietēji\n", id, task.id)
time.Sleep(100 * time.Millisecond) // Imitācija
continue
}
// Ja vietējā rinda ir tukša, mēģinām zagšanu
stolen := false
for _, queue := range otherQueues {
if queue == localQueue {
continue // Nezog no sevis
}
task, ok := queue.StealTask()
if ok {
fmt.Printf("Darbinieks %d zag uzdevumu %d\n", id, task.id)
time.Sleep(100 * time.Millisecond) // Imitācija
stolen = true
break // Veiksmīgi zagts, iziet
}
}
if !stolen {
// Ja neizdevās zagšanu, varbūt uzdevumi vairs nav
// Reāla plānotājā ir sarežģītāki mehānismi
// Demostrācijā vienkārši iziet pēc noteikta laika
fmt.Printf("Darbinieks %d gaida...\n", id)
time.Sleep(50 * time.Millisecond)
// Reāla scenārijā šeit būtu beigu vai parkošanas mehānisms
// return // Demostrācijā ļausim iziet
break // Vienkāršības pēc
}
}
}
func main() {
numWorkers := 4
numTasks := 20
taskQueues := make([]*TaskQueue, numWorkers)
for i := range taskQueues {
taskQueues[i] = &TaskQueue{}
}
// Nepareiza uzdevumu sadale demonstrācijai
for i := 0; i < numTasks; i++ {
queueIndex := i % 2 // Pirmās divas darba vietas ar vairāk uzdevumiem
taskQueues[queueIndex].AddTask(Task{id: i})
}
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
// Nododam atsauces uz visas rindas, lai darbinieks varētu "zagt"
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("Visas uzdevumi izpildīti")
}