Goroutines hakkında bilgi edinin

Tamamlandı

Eşzamanlılık, bir web sunucusunun aynı anda ancak otonom bir şekilde birden çok kullanıcı isteğiyle ilgilenirken yaptığı çalışma gibi bağımsız etkinliklerin bileşimidir. Eşzamanlılık günümüzde birçok programda mevcuttur. Web sunucuları bir örnektir, ancak toplu olarak önemli miktarda veriyi işlerken eşzamanlılık gereksinimini de görürsünüz.

Go'nun eşzamanlı programlar yazmak için iki stili vardır. Bunlardan biri, iş parçacıklarıyla diğer dillerde kullanmış olabileceğiniz geleneksel stildir. Bu modülde, goroutinler olarak bilinen bağımsız etkinlikler arasında süreçleri iletmek için değerlerin geçirildiği Go'nun stili hakkında bilgi edineceksiniz.

Eşzamanlılık hakkında ilk kez bilgi ediniyorsanız alıştırma yapmak için yazacağımız her kod parçasını gözden geçirmek için fazladan zaman harcamanızı öneririz.

Go'nun eşzamanlılık yaklaşımı

Genellikle, eşzamanlı programlar yazmanın en büyük sorunu işlemler arasında veri paylaşımıdır. Go, verileri kanallardan ileri geri geçirdiğinden, go iletişimle diğer programlama dillerinden farklı bir yaklaşım benimser. Bu yaklaşım, yalnızca bir etkinliğin (goroutine) verilere erişimi olduğu ve tasarım gereği yarış koşulu olmadığı anlamına gelir. Bu modülde goroutinler ve kanallar hakkında bilgi edindikçe Go'nun eşzamanlılık yaklaşımını daha iyi anlayacaksınız.

Go'nun yaklaşımı şu sloganda özetlenebilir: "Bellek paylaşarak iletişim kurmayın; bunun yerine iletişim kurarak bellek paylaşın." Bu yaklaşımı aşağıdaki bölümlerde ele alacağız, ancak İletişim Kurarak Belleği Paylaş blog gönderisinde daha fazla bilgi edinebilirsiniz.

Daha önce de belirttiğimiz gibi Go, düşük düzey eşzamanlılık temel öğelerini de içerir. Ancak bu modülde yalnızca Go'nun eşzamanlılık yaklaşımını ele alacağız.

Goroutin'leri keşfederek başlayalım.

Goroutines

Goroutine, işletim sisteminde sahip olduğunuz geleneksel etkinlik değil, basit bir iş parçacığında eş zamanlı bir etkinliktir. Çıkışa yazan bir programınız ve iki sayı ekleme gibi hesaplamalar sağlayan başka bir işleviniz olduğunu varsayalım. Eşzamanlı bir programda aynı anda her iki işlevi de çağıran birkaç goroutin olabilir.

Bir programın yürüttüğü ilk goroutine işlevinin main() olduğunu söyleyebiliriz. Başka bir goroutine oluşturmak istiyorsanız, işlevi çağırmadan önce anahtar sözcüğünü go kullanmanız gerekir, örneğin:

func main(){
    login()
    go launch()
}

Alternatif olarak, bu kodda olduğu gibi birçok programın goroutin oluşturmak için anonim işlevleri kullanmayı beğendiğini göreceksiniz:

func main(){
    login()
    go func() {
        launch()
    }()
}

Goroutinlerin nasıl çalıştığını görmek için eş zamanlı bir program yazalım.

Eş zamanlı program yazma

Yalnızca eşzamanlı bölüme odaklanmak istediğimizden, bir API uç noktasının yanıt verilip verilmediğini denetleyen mevcut bir programı kullanalım. Kod şu şekildedir:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    start := time.Now()

    apis := []string{
        "https://management.azure.com",
        "https://dev.azure.com",
        "https://api.github.com",
        "https://outlook.office.com/",
        "https://api.somewhereintheinternet.com/",
        "https://graph.microsoft.com",
    }

    for _, api := range apis {
        _, err := http.Get(api)
        if err != nil {
            fmt.Printf("ERROR: %s is down!\n", api)
            continue
        }

        fmt.Printf("SUCCESS: %s is up and running!\n", api)
    }

    elapsed := time.Since(start)
    fmt.Printf("Done! It took %v seconds!\n", elapsed.Seconds())
}

Önceki kodu çalıştırdığınızda aşağıdaki çıkışı alırsınız:

SUCCESS: https://management.azure.com is up and running!
SUCCESS: https://dev.azure.com is up and running!
SUCCESS: https://api.github.com is up and running!
SUCCESS: https://outlook.office.com/ is up and running!
ERROR: https://api.somewhereintheinternet.com/ is down!
SUCCESS: https://graph.microsoft.com is up and running!
Done! It took 1.658436834 seconds!

Burada olağan dışı bir şey yok, ama daha iyisini yapabiliriz. Belki tüm siteleri aynı anda kontrol edebiliriz? Program neredeyse iki saniye yerine 500 ms'den kısa sürede tamamlanabilir.

Kodun eşzamanlı olarak çalıştırmamız gereken bölümünün, siteye HTTP çağrısı yapan bölüm olduğuna dikkat edin. Başka bir deyişle, programın denetlediğini her API için bir goroutine oluşturmamız gerekir.

Goroutine oluşturmak için bir işlevi çağırmadan önce anahtar sözcüğünü go kullanmamız gerekir. Ancak orada bir işlevimiz yok. Şimdi bu kodu yeniden düzenleyelim ve aşağıdaki gibi yeni bir işlev oluşturalım:

func checkAPI(api string) {
    _, err := http.Get(api)
    if err != nil {
        fmt.Printf("ERROR: %s is down!\n", api)
        return
    }

    fmt.Printf("SUCCESS: %s is up and running!\n", api)
}

Döngüde for olmadığımız için anahtar sözcüğüne continue artık ihtiyaç duymadığımıza dikkat edin. İşlevin yürütme akışını durdurmak için anahtar sözcüğünü return kullanırız. Şimdi api başına bir goroutine oluşturmak için işlevdeki main() kodu değiştirmemiz gerekiyor, örneğin:

for _, api := range apis {
    go checkAPI(api)
}

Programı yeniden çalıştırın ve ne olduğunu görün.

Program artık API'leri denetlemiyor gibi görünüyor, değil mi? Aşağıdaki çıkışa benzer bir şey görebilirsiniz:

Done! It took 1.506e-05 seconds!

Çok hızlıydı! Neler oldu? Go döngüdeki her site için bir goroutine oluşturduğundan ve hemen bir sonraki satıra geçtiğinden programın bittiğini belirten son iletiyi görürsünüz.

İşlev çalışıyor gibi checkAPI görünmese de çalışıyor. Sadece bitirecek zamanı yoktu. Döngüden hemen sonra aşağıdaki gibi bir uyku süreölçeri eklerseniz ne olacağına dikkat edin:

for _, api := range apis {
    go checkAPI(api)
}

time.Sleep(3 * time.Second)

Şimdi programı yeniden çalıştırdığınızda aşağıdakine benzer bir çıkış görebilirsiniz:

ERROR: https://api.somewhereintheinternet.com/ is down!
SUCCESS: https://api.github.com is up and running!
SUCCESS: https://management.azure.com is up and running!
SUCCESS: https://dev.azure.com is up and running!
SUCCESS: https://outlook.office.com/ is up and running!
SUCCESS: https://graph.microsoft.com is up and running!
Done! It took 3.002114573 seconds!

Çalışıyor gibi görünüyor, değil mi? Tam olarak değil. Listeye yeni bir site eklemek isterseniz ne olur? Belki de üç saniye yeterli değildir. Nereden bileceksin ki? Yönetemezsiniz. Bunun daha iyi bir yolu olmalı ve bir sonraki bölümde kanallardan bahsederken bunu tartışacağız.