简体   繁体   English

操作系统线程是否在 go-routine 执行的 io 上被阻塞?

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

On my machine there are 4 logical processors.在我的机器上有 4 个逻辑处理器。 so there are four contexts P1 , P2 , P3 & P4 working with OS threads M1 , M2 , M3 & M4所以有四个上下文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

In the below code:在下面的代码中:

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

}

there are six go-routines that perform http.Get()有六个执行http.Get()的 go-routines


1) 1)

Does OS thread( M1 ) get blocked with go-routine( G1 ) on io( http.Get() )? OS线程( M1 )是否被io( http.Get() )上的go-routine( G1 )阻塞? on context P1在上下文P1

or或者

Does Go scheduler pre-empt go-routine( G1 ) from OS thread( M1 ) upon http.Get() ? Go 调度程序是否在http.Get() ) 上从 OS 线程 ( M1 ) 抢占 go-routine ( G1 ) ? and assign G2 to M1 ... if yes, on pre-emption of G1 , how G1 is managed by Goruntime to resume G1 upon completion of IO( http.Get )?并将G2分配给M1 ...如果是,在抢占G1时,Goruntime 如何管理G1以在完成 IO 后恢复G1http.Get )?

2) 2)

What is the api to retrieve context number(P) used for each go-routine(G)?检索用于每个 go-routine (G) 的上下文编号 (P) 的 api 是什么? for debugging purpose..用于调试目的..

3) we maintain critical section using counted semaphore for above reader writer problem using C pthreads library. 3)我们使用计数信号量维护临界区,使用 C pthreads 库解决上述读写器问题。 Why are we not getting into the usage of critical sections using go-routines and channels?为什么我们不使用 go-routines 和通道来使用关键部分?

No, it doesn't block.不,它不会阻塞。 My rough (and unsourced, I picked it up through osmosis) understanding is that whenever a goroutine wants to perform a "blocking" I/O that has an equivalent non-blocking version,我粗略的(并且没有来源,我是通过 osmosis 得到的)理解是,每当一个 goroutine 想要执行一个具有等效非阻塞版本的“阻塞”I/O 时,

  1. Performs a non-blocking version instead.改为执行非阻塞版本。
  2. Records its own ID in a table somewhere keyed by the handle it is "blocking" on.将它自己的 ID 记录在一个由它“阻塞”的句柄键入的表中。
  3. Transfers responsibility for the completion to a dedicated thread which sits in a select loop (or poll or whatever equivalent is available) waiting for such operations to unblock, and将完成的责任转移到一个专用线程,该线程位于select循环(或poll或任何可用的等效项)中,等待此类操作解除阻塞,并且
  4. Suspends itself, freeing up its OS thread (M) to run another goroutine.挂起自己,释放其操作系统线程(M)以运行另一个 goroutine。

When the I/O operation unblocks, the select-loop looks in the table to figure out which goroutine was interested in the result, and schedules it to be run.当 I/O 操作解除阻塞时,选择循环在表中查找哪个 goroutine 对结果感兴趣,并安排它运行。 In this way, goroutines waiting for I/O do not occupy an OS thread.这样,等待 I/O 的 goroutine 就不会占用一个 OS 线程。

In case of I/O that can't be done non-blockingly, or any other blocking syscall, the goroutine executes the syscall through a runtime function that marks its thread as blocked, and the runtime will create a new OS thread for goroutines to be scheduled on.在无法以非阻塞方式完成的 I/O 或任何其他阻塞系统调用的情况下,goroutine 通过运行时 function 执行系统调用,将其线程标记为阻塞,运行时将为 goroutine 创建一个新的 OS 线程被安排在。 This maintains the ability to have GOMAXPROCS running (not blocked) goroutines.这保持了让 GOMAXPROCS 运行(未阻塞)goroutines 的能力。 This doesn't cause very much thread bloat for most programs, since the most common syscalls for dealing with files, sockets, etc. have been made async-friendly.对于大多数程序来说,这不会导致太多的线程膨胀,因为用于处理文件的最常见系统调用 sockets 等已变得异步友好。 (Thanks to @JimB for reminding me of this, and the authors of the helpful linked answers.) (感谢@JimB 提醒我这一点,以及有用的链接答案的作者。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM