บันทึก:
ตั้งแต่ Go 1.5 GOMAXPROCS ถูกตั้งค่าเป็นจำนวนคอร์ของฮาร์ดแวร์: golang.org/doc/go1.5#runtimeด้านล่างคำตอบเดิมก่อน 1.5
เมื่อคุณเรียกใช้โปรแกรม Go โดยไม่ได้ระบุตัวแปรสภาพแวดล้อม GOMAXPROCS Go goroutines จะถูกกำหนดเวลาสำหรับการดำเนินการในเธรด OS เดียว อย่างไรก็ตามเพื่อให้โปรแกรมดูเหมือนเป็นแบบมัลติเธรด (นั่นคือสิ่งที่ goroutines มีไว้เพื่อใช่หรือไม่) ตัวกำหนดตารางเวลา Go บางครั้งต้องเปลี่ยนบริบทการดำเนินการเพื่อให้ goroutine แต่ละตัวสามารถทำงานได้
ดังที่ฉันได้กล่าวไปแล้วเมื่อไม่ได้ระบุตัวแปร GOMAXPROCS รันไทม์ Go จะได้รับอนุญาตให้ใช้เธรดเดียวเท่านั้นดังนั้นจึงเป็นไปไม่ได้ที่จะสลับบริบทการดำเนินการในขณะที่ goroutine กำลังทำงานแบบเดิม ๆ เช่นการคำนวณหรือแม้แต่ IO (ซึ่งแมปกับฟังก์ชัน C ธรรมดา ). บริบทสามารถเปลี่ยนได้ก็ต่อเมื่อใช้ Go concurrency primitives เช่นเมื่อคุณเปิด chans หลายตัวหรือ (นี่คือกรณีของคุณ) เมื่อคุณบอกให้ตัวกำหนดตารางเวลาเปลี่ยนบริบทอย่างชัดเจน - นี่คือสิ่งที่runtime.Gosched
มีไว้สำหรับ
ดังนั้นในระยะสั้นเมื่อบริบทการดำเนินการในหนึ่ง goroutine ถึงการGosched
โทรตัวกำหนดตารางเวลาจะได้รับคำสั่งให้เปลี่ยนการดำเนินการเป็น goroutine อื่น ในกรณีของคุณมีสอง goroutines หลัก (ซึ่งหมายถึงหัวข้อ 'หลัก' ของโปรแกรม) go say
และเพิ่มเติมที่คุณได้สร้างขึ้นด้วย หากคุณลบการGosched
โทรบริบทการดำเนินการจะไม่ถูกโอนจาก goroutine ตัวแรกไปยังตัวที่สองดังนั้นจึงไม่มี 'โลก' สำหรับคุณ เมื่อGosched
มีอยู่ตัวกำหนดตารางเวลาจะโอนการดำเนินการในการวนซ้ำแต่ละลูปจาก goroutine ตัวแรกไปยังครั้งที่สองและในทางกลับกันคุณจึงมีคำว่า "hello" และ "world" แทรกอยู่
FYI สิ่งนี้เรียกว่า 'การทำงานหลายอย่างแบบร่วมมือกัน': goroutines ต้องให้การควบคุมกับ goroutines อื่น ๆ อย่างชัดเจน แนวทางที่ใช้ในระบบปฏิบัติการร่วมสมัยส่วนใหญ่เรียกว่า 'preemptive multitasking': เธรดการดำเนินการไม่เกี่ยวข้องกับการถ่ายโอนการควบคุม ตัวกำหนดตารางเวลาจะสลับบริบทการดำเนินการอย่างโปร่งใสไปแทน วิธีการแบบร่วมมือมักใช้ในการใช้ 'เธรดสีเขียว' นั่นคือโครูทีนพร้อมกันเชิงตรรกะซึ่งไม่ได้แมปเธรด 1: 1 กับ OS - นี่คือวิธีการใช้รันไทม์ Go และ goroutines
อัปเดต
ฉันได้กล่าวถึงตัวแปรสภาพแวดล้อม GOMAXPROCS แต่ไม่ได้อธิบายว่ามันคืออะไร ถึงเวลาแก้ไขปัญหานี้
เมื่อตัวแปรนี้ถูกตั้งค่าเป็นจำนวนบวกN
รันไทม์ Go จะสามารถสร้างN
เธรดเนทีฟได้สูงสุดซึ่งเธรดสีเขียวทั้งหมดจะถูกกำหนดเวลา Native thread คือเธรดชนิดหนึ่งที่สร้างโดยระบบปฏิบัติการ (เธรด Windows, pthreads ฯลฯ ) ซึ่งหมายความว่าถ้าN
มากกว่า 1 เป็นไปได้ว่า goroutines จะถูกกำหนดเวลาให้ดำเนินการในเธรดเนทีฟที่แตกต่างกันและดังนั้นจึงรันแบบขนาน (อย่างน้อยก็ขึ้นอยู่กับความสามารถของคอมพิวเตอร์ของคุณ: หากระบบของคุณใช้โปรเซสเซอร์มัลติคอร์ มีแนวโน้มว่าเธรดเหล่านี้จะขนานกันอย่างแท้จริงหากโปรเซสเซอร์ของคุณมีคอร์เดี่ยวการทำงานหลายอย่างล่วงหน้าที่นำมาใช้ในเธรด OS จะสร้างการมองเห็นการทำงานแบบขนาน)
เป็นไปได้ที่จะตั้งค่าตัวแปร GOMAXPROCS โดยใช้runtime.GOMAXPROCS()
ฟังก์ชันแทนการตั้งค่าตัวแปรสภาพแวดล้อมล่วงหน้า ใช้สิ่งนี้ในโปรแกรมของคุณแทนปัจจุบันmain
:
func main() {
runtime.GOMAXPROCS(2)
go say("world")
say("hello")
}
ในกรณีนี้คุณสามารถสังเกตผลลัพธ์ที่น่าสนใจได้ เป็นไปได้ว่าคุณจะได้รับบรรทัด "สวัสดี" และ "โลก" ที่พิมพ์แทรกสลับกันอย่างไม่สม่ำเสมอเช่น
hello
hello
world
hello
world
world
...
สิ่งนี้สามารถเกิดขึ้นได้หาก goroutines ถูกกำหนดเวลาให้แยกเธรด OS นี่คือวิธีการทำงานของมัลติทาสก์แบบ preemptive (หรือการประมวลผลแบบขนานในกรณีของระบบมัลติคอร์): เธรดจะขนานกันและเอาต์พุตที่รวมกันนั้นไม่แน่นอน BTW คุณสามารถออกหรือลบการGosched
โทรได้ดูเหมือนว่าจะไม่มีผลเมื่อ GOMAXPROCS ใหญ่กว่า 1
ต่อไปนี้คือสิ่งที่ฉันได้รับจากการรันโปรแกรมหลายครั้งพร้อมการruntime.GOMAXPROCS
โทร
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
ดูบางครั้งผลลัพธ์ก็สวยบางครั้งก็ไม่ได้ ความไม่แน่นอนในการดำเนินการ :)
การปรับปรุงอื่น ๆ
ดูเหมือนว่าในเวอร์ชันที่ใหม่กว่าของ Go compiler Go runtime จะบังคับให้ goroutines ไม่เพียงให้ผลตอบแทนจากการใช้งาน primitives พร้อมกันเท่านั้น แต่ยังรวมถึงการเรียกระบบ OS ด้วย ซึ่งหมายความว่าบริบทการดำเนินการสามารถสลับระหว่าง goroutines ได้เช่นกันในการเรียกฟังก์ชัน IO ดังนั้นในคอมไพเลอร์ Go ล่าสุดจึงเป็นไปได้ที่จะสังเกตพฤติกรรมที่ไม่แน่นอนแม้ว่า GOMAXPROCS จะไม่ได้ตั้งค่าหรือตั้งค่าเป็น 1 ก็ตาม