Sobes.tech
Middle

როგორ შეიძლება თავიდან აიცილოთ ურთიერთშეზღუდვის (deadlock) სიტუაცია Go-ის პროგრამაში?

sobes.tech AI

პასუხი AI-სგან

გააზიარებითი ბლოკირება Go-ში ყველაზე ხშირად წარმოიქმნება მუტექსებისა და არხების არასათანადო გამოყენებისას. მასზე თავიდან აცილება შესაძლებელია შემდეგი გზებით:

  • მუტექსების წესრიგიანი დაჭერა: როდესაც რამდენიმე მუტექსს იჭერთ, ყოველთვის გააკეთეთ ეს ერთსა და იმავე წესრიგში ყველა გორუტინაში.
  • ტაიმაუტები ბლოკირებისთვის: გამოიყენეთ კონტექსტები ტაიმაუტებით, როდესაც ელით ბლოკირებას ან არხებიდან მონაცემების მიღებას, რათა თავიდან აიცილოთ უსასრულო მოლოდინი.
  • არასათანადო ბუფერული არხები: გაიგეთ, რომ არასათანადო ბუფერული არხები მოითხოვს როგორც გამგზავნს, ასევე მიმღებს, რათა გაგრძელდეს შესრულება. არასათანადო გამოყენება შეიძლება გამოიწვიოს ბლოკირება.
  • ბუფერული არხები: სწორად შეარჩიეთ არხის ბუფერის ზომა. ძალიან პატარა ბუფერი შეიძლება გამოიწვიოს ბლოკირება, თუ გამგზავნები და მიმღებები არ არის სინქრონიზებული.
  • select-ის გამოყენება: როდესაც მუშაობთ რამდენიმე არხთან, გამოიყენეთ select ოპერატორი default-ის ან ტაიმაუტის ბლოკით, რათა თავიდან აიცილოთ ბლოკირება ერთ არხზე მოლოდინში.
  • კოდის ანალიზი: გამოიყენეთ სტატიკური ანალიზი (go vet, staticcheck) და ინსტრუმენტები მონაცემთა შეჯახების გამოვლენისათვის (go run -race), რომლებიც ასევე დაგეხმარებათ შესაძლო взаимных ბლოკირებების ადგილების გამოვლენაში.
  • რესურსების ჰიერქია: თუ რესურსებს აქვთ ჰიერქია, იჭერთ მათ ზევითიდან ქვემოთ.
  • ციკლური დამოკიდებულებების თავიდან აცილება: არ შექმნათ სიტუაციები, სადაც გორუტინა A ელოდება რესურსს, რომელიც დაკავებულია B-ით, ხოლო B ელოდება რესურსს, რომელიც დაკავებულია A-ით.

მაგალითი select-ის გამოყენებით ტაიმაუტთან:

import (
	"context"
	"time"
)

func მაგალითი(ch chan int) {
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()

	select {
	case val := <-ch:
		// მონაცემის დამუშავება
		_ = val
	case <-ctx.Done():
		// ტაიმაუტი მოხდა
	}
}