Middle
Workshopping nədir?
sobes.tech Süni İntellekt
AI-dan cavab
İş oğurlama (work stealing), çox iplikli sistemlərdə yük balanslaşdırma mexanizmi olub, burada işsiz qalan işçi (worker) digər işçinin növbəsindən tapşırıqları " oğurlayır".
Əsas xüsusiyyətlər:
- Mərkəzləşdirilməmiş: Hər bir işçi öz yerli tapşırıq növbəsini idarə edir.
- Aktiv: İşsiz işçi digər işçilərdən aktiv şəkildə iş axtarır.
- Yüksək performans: qeyri-bərabər yük altında effektivdir.
Golang-də scheduler-də istifadə olunur və gorutinləri əməliyyat sisteminin (OS) M iş parçalarına paylayır. Bir M öz işini (gorutin paketini P üzərində) tamamladıqda, digər P-lərin yerli növbələrindən gorutinləri axtarır.
// İş oğurlama konseptini göstərən pseudokod
package main
import "fmt"
import "sync"
import "time"
type Task struct {
id int
}
// Tapşırıq növbəsinin simulasyonu
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
}
// Digər növbədən " oğurlamağa" cəhd
func (q *TaskQueue) StealTask() (Task, bool) {
q.mu.Lock()
defer q.mu.Unlock()
if len(q.tasks) < 2 { // Az tapşırıq varsa oğurlamırıq
return Task{}, false
}
// Ortadan və ya sonundan oğurlama, lokal çıxarışla qarşılaşmamaq üçün
index := len(q.tasks) / 2
task := q.tasks[index]
q.tasks = append(q.tasks[:index], q.tasks[index+1:]...)
return task, true
}
// İşçi threadinin simulasyonu
func worker(id int, localQueue *TaskQueue, otherQueues []*TaskQueue, wg *sync.WaitGroup) {
defer wg.Done()
for {
// Lokal növbədən tapşırıq almağa cəhd
task, ok := localQueue.GetLocalTask()
if ok {
fmt.Printf("İşçi %d, tapşırıq %d yerli olaraq icra edir\n", id, task.id)
time.Sleep(100 * time.Millisecond) // İşin simulasyonu
continue
}
// Əgər yerli növbə boşdursa, oğurlamağa cəhd
stolen := false
for _, queue := range otherQueues {
if queue == localQueue {
continue // Öz növbəsindən oğurlamırıq
}
task, ok := queue.StealTask()
if ok {
fmt.Printf("İşçi %d, tapşırıq %d oğurladı\n", id, task.id)
time.Sleep(100 * time.Millisecond) // İşin simulasyonu
stolen = true
break // Uğurlu oğurlama, oğurlama döngüsündən çıx
}
}
if !stolen {
// Əgər oğurlaya bilməyibsə, tapşırıq qalmamış ola bilər
// Reallıqda daha mürəkkəb bitmə mexanizmləri var
// Demo üçün, sadəcə bir müddət gözlədikdən sonra çıxırıq
fmt.Printf("İşçi %d, inaktiftir, gözləyir...\n", id)
time.Sleep(50 * time.Millisecond)
// Reallıqda, burada bitmə və ya thread parketmə mexanizmi olardı
// return // Demo üçün, çıxmağa icazə veririk
break // Sadələşdirmə üçün simulasiya
}
}
}
func main() {
numWorkers := 4
numTasks := 20
taskQueues := make([]*TaskQueue, numWorkers)
for i := range taskQueues {
taskQueues[i] = &TaskQueue{}
}
// Tapşırıqları qeyri-bərabər paylayırıq, work stealing üçün
for i := 0; i < numTasks; i++ {
queueIndex := i % 2 // İlk iki işçiyə daha çox tapşırıq
taskQueues[queueIndex].AddTask(Task{id: i})
}
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
// Bütün növbələrə referanslar ötürürük, işçi " oğurlaya" bilsin
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("Bütün tapşırıqlar yerinə yetirildi")
}