【发布时间】:2020-05-08 23:38:37
【问题描述】:
在我的机器上有 4 个逻辑处理器。所以有四个上下文P1、P2、P3和P4与操作系统线程一起工作M1、M2、M3和M4
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
在下面的代码中:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func getPage(url string) (int, error) {
resp, err := http.Get(url)
if err != nil {
return 0, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, err
}
return len(body), nil
}
func worker(urlChan chan string, sizeChan chan<- string, i int) {
for {
url := <-urlChan
length, err := getPage(url)
if err == nil {
sizeChan <- fmt.Sprintf("%s has length %d (%d)", url, length, i)
} else {
sizeChan <- fmt.Sprintf("%s has error %s (%d)", url, err, i)
}
}
}
func main() {
urls := []string{"http://www.google.com/", "http://www.yahoo.com",
"http://www.bing.com", "http://bbc.co.uk", "http://www.ndtv.com", "https://www.cnn.com/"}
urlChan := make(chan string)
sizeChan := make(chan string)
for i := 0; i < len(urls); i++ {
go worker(urlChan, sizeChan, i)
}
for _, url := range urls {
urlChan <- url
}
for i := 0; i < len(urls); i++ {
fmt.Printf("%s\n", <-sizeChan)
}
}
有六个 go-routines 执行http.Get()
1)
操作系统线程(M1) 是否被 io(http.Get()) 上的 go-routine(G1) 阻塞?在上下文P1
或
Go 调度程序是否在http.Get() 上从操作系统线程(M1) 抢占 go-routine(G1)?并将G2 分配给M1...如果是,在G1 的优先权上,Goruntime 如何管理G1 以在IO 完成后恢复G1(http.Get)?
2)
检索用于每个 go-routine(G) 的上下文编号 (P) 的 api 是什么?用于调试目的..
3) 我们使用 C pthreads 库为上述读写器问题使用计数信号量维护关键部分。为什么我们不使用 go-routines 和通道来使用临界区?
【问题讨论】:
-
用
GODEBUG=schedtrace=1000运行程序,查看goroutine调度轨迹 -
请注意,虽然并发执行的用户线程仅限于 GOMAXPROCS,但运行时将生成所需数量的线程来服务阻塞系统调用,这当然包括任何实际的阻塞 IO 调用。
标签: c multithreading go goroutine