Not:
Go 1.5'ten itibaren, GOMAXPROCS donanımın çekirdek sayısına ayarlanmıştır: golang.org/doc/go1.5#runtime , 1.5'ten önceki orijinal cevabın altında.
GOMAXPROCS ortam değişkenini belirtmeden Go programını çalıştırdığınızda, Go programlarının tek bir işletim sistemi iş parçacığında yürütülmesi planlanır. Bununla birlikte, programın çok iş parçacıklı görünmesini sağlamak için (gorutinler bunun içindir, değil mi?), Go planlayıcısının bazen yürütme bağlamını değiştirmesi gerekir, böylece her bir gorutin kendi işini yapabilir.
Dediğim gibi, GOMAXPROCS değişkeni belirtilmediğinde, Go çalışma zamanının yalnızca bir iş parçacığı kullanmasına izin verilir, bu nedenle, gorutin hesaplamalar veya hatta IO (düz C işlevleriyle eşlenir) gibi bazı geleneksel işleri gerçekleştirirken yürütme bağlamlarını değiştirmek imkansızdır. ). Bağlam, yalnızca Go eşzamanlılık ilkelleri kullanıldığında, örneğin birkaç kanalı açtığınızda veya programlayıcıya bağlamları değiştirmesini açıkça söylediğinizde (bu sizin durumunuzdur) değiştirilebilir - bunun için budur runtime.Gosched
.
Kısaca, bir gruptaki yürütme bağlamı çağrıya ulaştığında Gosched
, programlayıcıya yürütmeyi başka bir gorutine değiştirme talimatı verilir. Sizin durumunuzda, ana (programın 'ana' iş parçacığını temsil eden) ve ek olarak oluşturduğunuz iki gorutin vardır go say
. Gosched
Çağrıyı kaldırırsanız , yürütme bağlamı asla birinci gorutinden ikinciye aktarılmaz, dolayısıyla sizin için "dünya" olmaz. Zaman Gosched
mevcut olduğu, zamanlayıcı aktarır 'Merhaba' ve 'dünya içiçe böylece tam tersi saniye ve yardımcısı ilk goroutine her döngünün yürütme.
Bilginize, buna 'işbirliğine dayalı çoklu görev' denir: gorutinler kontrolü açıkça diğer gorutinlere vermelidir. Çoğu çağdaş işletim sisteminde kullanılan yaklaşım 'önleyici çoklu görev' olarak adlandırılır: yürütme iş parçacıkları kontrol aktarımı ile ilgilenmez; programlayıcı bunun yerine yürütme bağlamlarını şeffaf bir şekilde değiştirir. İşbirlikçi yaklaşım, 'yeşil iş parçacıkları'nı, yani işletim sistemi iş parçacıklarıyla 1: 1 eşlemeyen mantıksal eşzamanlı eşgüdümleri uygulamak için sıklıkla kullanılır - bu, Go çalışma zamanı ve onun gorutinlerinin uygulanma şeklidir.
Güncelleme
GOMAXPROCS ortam değişkeninden bahsetmiştim ama ne olduğunu açıklamadım. Bunu düzeltmenin zamanı geldi.
Bu değişken pozitif bir sayıya ayarlandığında N
, Go çalışma zamanı N
, üzerinde tüm yeşil iş parçacıklarının planlanacağı yerel iş parçacıklarını oluşturabilir . Yerel iş parçacığı, işletim sistemi (Windows iş parçacıkları, pthreads vb.) Tarafından oluşturulan bir tür iş parçacığıdır. Bu N
, 1'den büyükse, gorutinlerin farklı yerel iş parçacıklarında yürütülmek üzere programlanacağı ve sonuç olarak paralel olarak çalışacağı anlamına gelir (en azından bilgisayarınızın yeteneklerine kadar: sisteminiz çok çekirdekli işlemciye dayanıyorsa, büyük olasılıkla bu iş parçacıkları gerçekten paralel olacaktır; işlemcinizin tek çekirdeği varsa, işletim sistemi iş parçacıklarında uygulanan önleyici çoklu görev paralel yürütme görünürlüğü yaratacaktır).
Ortam değişkenini runtime.GOMAXPROCS()
önceden ayarlamak yerine fonksiyon kullanarak GOMAXPROCS değişkenini ayarlamak mümkündür . Programınızda şu anki yerine şuna benzer bir şey kullanın main
:
func main() {
runtime.GOMAXPROCS(2)
go say("world")
say("hello")
}
Bu durumda ilginç sonuçlar gözlemleyebilirsiniz. Düzensiz aralıklarla basılmış "merhaba" ve "dünya" satırlarını almanız mümkündür, örn.
hello
hello
world
hello
world
world
...
Bu, gorutinler işletim sistemi iş parçacıklarını ayırmak üzere programlandıysa olabilir. Aslında bu, önleyici çoklu görevin (veya çok çekirdekli sistemlerde paralel işlemenin) nasıl çalıştığıdır: iş parçacıkları paraleldir ve birleşik çıktıları belirsizdir. BTW, Gosched
aramayı bırakabilir veya kaldırabilirsiniz , GOMAXPROCS 1'den büyük olduğunda hiçbir etkisi yok gibi görünüyor.
Aşağıda, runtime.GOMAXPROCS
çağrı ile programın birkaç çalıştırmasında elde ettiğim şey var .
hyperplex /tmp % go run test.go
hello
hello
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
hello
hello
hello
hello
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world
Bak, bazen çıktı güzel, bazen değil. Eylemdeki belirsizlik :)
Başka bir güncelleme
Görünüşe göre Go derleyicisinin daha yeni sürümlerinde Go çalışma zamanı, gorutinleri yalnızca eşzamanlılık ilkelleri kullanımında değil, aynı zamanda işletim sistemi sistem çağrılarında da üretmeye zorlar. Bu, yürütme bağlamının, IO fonksiyonları çağrılarında da gorutinler arasında değiştirilebileceği anlamına gelir. Sonuç olarak, son Go derleyicilerinde, GOMAXPROCS ayarlanmadığında veya 1'e ayarlandığında bile belirsiz davranış gözlemlemek mümkündür.