برنامه نویسی

Ooms را با semahores متوقف کنید – جامعه dev

GO نوشتن کد همزمان را آسان می کند – فقط به Dosomething () اضافه کنید و خاموش هستید. اما اگر مراقب نیستید ، می توانید خدمات خود را با بسیاری از گوروس ها تحت الشعاع قرار دهید. در اینجا نحوه جلوگیری از بروز تصادفی خود با استفاده از یک semaphore ساده و مؤثر آورده شده است.

Semaphore یک الگوی همزمانی است که مدتها قبل از آن وجود داشته است ، اما اجرای آن با کانال های GO بسیار آسان است.

در علوم کامپیوتر موارد استفاده زیادی برای semaphores وجود دارد ، اما یکی از کاربردی ترین آنها در GO محدود کردن تعداد Goroutines برنامه های برنامه شما است.

گوروتین ها ارزان هستند اما رایگان نیستند. گوروهای بی حد و حصر می توانند به دلیل مشاجره CPU ، استفاده از حافظه فراری (پشته و پشته) و حتی نشت گوروتین منجر به عملکرد تخریب شده شوند.

مثال:
قطعه کد زیر از Go-Chi اقتباس شده است: https://github.com/go-chi/chi. این یک سرور وب ساده با یک نقطه پایانی HTTP ایجاد می کند تا پرونده های بزرگی را که به عنوان درخواست های چند منظوره ارائه شده است ، پردازش کند و از یک semaphore برای محدود کردن همزمانی جهانی استفاده می کند ، اطمینان حاصل می کند که این سرویس هرگز بیش از تعداد ثابت پرونده ها به طور همزمان پردازش نمی کند – صرف نظر از اینکه تعداد کاربران به نقطه پایانی ضربه می زنند.

func main() {
    maxGoroutinesEnv := os.Getenv("MAX_GOROUTINES")
    maxGoroutines, err := strconv.Atoi(maxGoroutinesEnv)
    if err != nil {
        log.Fatalf("failed to load MAX_GOROUTINES env var %w", err)
    }

    // create semaphore
    sem := NewSemaphore(maxGoroutines)

    r := chi.NewRouter()
    r.Use(middleware.Logger)
    r.Get("https://dev.to/", func(w http.ResponseWriter, r *http.Request) {
        processListOfLargeCustomerProvidedConfigs(w, r, sem)
    })
    http.ListenAndServe(":3000", r)
}

func processListOfLargeCustomerProvidedConfigs(
    w http.ResponseWriter,
    r *http.Request,
    sem *Semaphore,
) {
    err := r.ParseMultipartForm(50 << 20)
    if err != nil {
        errMsg := fmt.Sprintf("could not parse multipart form: %w", err)
        http.Error(w, errMsg, http.StatusBadRequest)
        return
    }

    files := r.MultipartForm.File["configs"]
    if len(files) == 0 {
        http.Error(w, "no files in request", http.StatusBadRequest)
        return
    }

    for _, f := range files {
        // blocks if the semaphore is "full"
        sem.Acquire(1)

        go func(f *multipart.FileHeader) {
            defer sem.Release(1)
            // memory and cpu intensive task
            processFile(f)
        }(f)
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

همانطور که در بالا مشاهده می کنید ، هر بار که سعی در ایجاد یک goroutine برای پردازش یک فایل داریم ، اگر سمیفور “پر” باشد و به طور خودکار پس از انتشار یک قطعه کار ، به طور خودکار ادامه می دهیم.

اجرای حداقل semaphore:
در اینجا اجرای کامل مورد استفاده در مثال آورده شده است:

type Semaphore struct {
    c chan struct{}
}

func NewSemaphore(w int) *Semaphore {
    return &Semaphore{
        // create a buffered channel with capacity
       // equal to the weight of the semaphore
        c: make(chan struct{}, w),
    }
}

func (s *Semaphore) Acquire(w int) {
    for range w {
        // Send an empty struct to the channel.
        // Blocks if the channel is full — meaning we've  reached our   concurrency limit.
        // We use `struct{}` to avoid extra allocations.
        s.c <- struct{}{}
    }
}

func (s *Semaphore) Release(w int) {
        // pull the desired amount of work
        // out of the semaphore channel
    for range w {
        <-s.c
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

📦 کتابخانه را ترجیح می دهید؟
و اگر می خواهید یک semaphore را حتی سریعتر اجرا کنید ، می توانید یکی را در اینجا پیدا کنید: https://pkg.go.dev/golang.org/x/sync/semaphore

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا