Nedir bu runtime.Gosched()?
Çoğu Gopher tarafından bilindiği üzere Go multithreading olayını çözümlemek için direkt olarak kernel space içerisinde schedule edilen native OS threadlerinden faydalanmak yerine, genel olarak, daha hafif ve etkin bir çözüm olan ve başlığı “green threads” altına giren, bir runtime ya da VM tarafından schedule edilen thread yapısını kullanmıştır. Bunların Go ekosistemindeki muadili “goroutine” olmaktadır.
runtime.Gosched() tamamen scheduler’in kaput altında çalışan modelleriyle ilgili olduğu için biraz da scheduler arkaplanından bahsetmem gerekecek.
Öncelikle Go scheduler üç ana entity kullanır:

Büyük ihtimalle dikkatinizi çeken ilk nokta C kısmı olmuştur. Context, basitçe, bir task’ın (burada goroutineler oluyor) yarıda kesilip sonradan kesim noktasından devam ettirilebilmesi için kullanılan küçük bir veri grubudur. Aslında bu parça thread içerisinde bütünleşik olarak gelir ancak soyutlamayı en aza çekmek için böyle bir gösterim yaptım.
Burada anlaşılan üzere 1:1 thread-context maplaması var. Bu da demek oluyor ki GOMAXPROCS aslında Goroutinelerin üzerine çoklanacağı (multiplexing) native thread sayısını belirtir, bu da doğru orantılı olarak context sayısıyla ilişkilidir.
Peki bunun runtime.Gosched() ile ne ilgisi var? Gosched’in görevi Context Switching yaparak, özellikle GOMAXPROCS=1 olduğunda, birden fazla Goroutine olan ortamlarda “execution” aşamasını diğer Goroutinelere aktararak onlara da çalışma şansı verip multitaskingi sağlamaktır. Buna “cooperative multitasking” denilmekte. Yani tasklar birbirleri arasında dönüşümlü olarak çalışarak multitasking’i yaratırlar.
Şimdi aşağıdaki kod örneği üzerinden gidelim:
Kod örneğine baktığımızda 2 Goroutine mevcut ve üzerlerinde koşabilecekleri tek bir native thread olduğunu görüyoruz.
Bunun yanında, elimizde printTime isimli, 5 defa, 1 milisaniye bloklayıp ardından zamanı basan bir fonksiyon mevcut. Buradaki bloklama kısmı önemli.
Bu örnek çalıştırıldığı zaman, ekrana 10 defa zamanı basacaktır. Ama nasıl? Hiçbir yerde context switching yapılmıyor.
Aslında yapılıyor. time.Sleep, printTime goroutinesini park eder ve execution context’i main’e aktarır, zamanı geldiğinde ise yine printTime’deki 12. satırdan devam eder. Bu bir Futex işlemi. Ona burada değinmeyeceğim. Yani bu örnekte açık açık Gosched’i çağırmaya gerek yok.
Bir de 11. satırı silip deneyelim.
