簡體   English   中英

操作系統線程是否在 go-routine 執行的 io 上被阻塞?

[英]Does OS thread get blocked on io performed by go-routine?

在我的機器上有 4 個邏輯處理器。 所以有四個上下文P1P2P3P4與操作系統線程M1M2M3M4一起使用

$ 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)
    }

}

有六個執行http.Get()的 go-routines


1)

OS線程( M1 )是否被io( http.Get() )上的go-routine( G1 )阻塞? 在上下文P1

或者

Go 調度程序是否在http.Get() ) 上從 OS 線程 ( M1 ) 搶占 go-routine ( G1 ) ? 並將G2分配給M1 ...如果是,在搶占G1時,Goruntime 如何管理G1以在完成 IO 后恢復G1http.Get )?

2)

檢索用於每個 go-routine (G) 的上下文編號 (P) 的 api 是什么? 用於調試目的..

3)我們使用計數信號量維護臨界區,使用 C pthreads 庫解決上述讀寫器問題。 為什么我們不使用 go-routines 和通道來使用關鍵部分?

不,它不會阻塞。 我粗略的(並且沒有來源,我是通過 osmosis 得到的)理解是,每當一個 goroutine 想要執行一個具有等效非阻塞版本的“阻塞”I/O 時,

  1. 改為執行非阻塞版本。
  2. 將它自己的 ID 記錄在一個由它“阻塞”的句柄鍵入的表中。
  3. 將完成的責任轉移到一個專用線程,該線程位於select循環(或poll或任何可用的等效項)中,等待此類操作解除阻塞,並且
  4. 掛起自己,釋放其操作系統線程(M)以運行另一個 goroutine。

當 I/O 操作解除阻塞時,選擇循環在表中查找哪個 goroutine 對結果感興趣,並安排它運行。 這樣,等待 I/O 的 goroutine 就不會占用一個 OS 線程。

在無法以非阻塞方式完成的 I/O 或任何其他阻塞系統調用的情況下,goroutine 通過運行時 function 執行系統調用,將其線程標記為阻塞,運行時將為 goroutine 創建一個新的 OS 線程被安排在。 這保持了讓 GOMAXPROCS 運行(未阻塞)goroutines 的能力。 對於大多數程序來說,這不會導致太多的線程膨脹,因為用於處理文件的最常見系統調用 sockets 等已變得異步友好。 (感謝@JimB 提醒我這一點,以及有用的鏈接答案的作者。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM