Блокируется ли поток ОС на io, выполняемом подпрограммой go? - PullRequest
0 голосов
/ 09 мая 2020

На моей машине 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 -программ, которые выполняют http.Get()


1)

Есть ли ОС поток (M1) заблокирован с помощью go -программы (G1) на io (http.Get())? в контексте P1

или

Запрещает ли Go планировщик go -программу (G1) из потока ОС (M1) при http.Get()? и назначьте G2 на M1 ... если да, то при преимущественном использовании G1, как Goruntime управляет G1, чтобы возобновить G1 после завершения ввода-вывода (http.Get)?

2)

Какой API для получения номера контекста (P) используется для каждой go -программы (G)? для целей отладки ..

3) мы поддерживаем критическую секцию, используя подсчитанный семафор для указанной выше проблемы читателя-писателя с использованием библиотеки C pthreads. Почему мы не используем критические секции, используя go -программы и каналы?

1 Ответ

2 голосов
/ 09 мая 2020

Нет, не блокирует. Мое приблизительное (и неподтвержденное, я понял это через осмос) понимание состоит в том, что всякий раз, когда горутина хочет выполнить "блокирующий" ввод-вывод, который имеет эквивалентную неблокирующую версию,

  1. Выполняет не -blocking version вместо этого.
  2. Записывает свой собственный идентификатор в таблицу где-нибудь с ключом дескриптора, который он «блокирует».
  3. Передает ответственность за завершение на выделенный поток, который находится в select l oop (или poll или любой другой эквивалент) ожидает разблокировки таких операций, и
  4. приостанавливает себя, освобождая свой поток ОС (M) для запуска другой горутины.

Когда операция ввода-вывода разблокируется, select-l oop просматривает таблицу, чтобы выяснить, какая горутина была заинтересована в результате, и планирует ее запуск. Таким образом, горутины, ожидающие ввода-вывода, не занимают поток ОС.

В случае ввода-вывода, который не может быть выполнен без блокировки, или любого другого блокирующего системного вызова, горутина выполняет системный вызов через функцию времени выполнения, которая помечает свой поток как заблокированный, и среда выполнения создаст новый поток ОС для горутин, которые будут запланированы. Это поддерживает возможность GOMAXPROCS запускать (не блокировать) горутины. Это не вызывает большого раздува потока для большинства программ, поскольку наиболее распространены системные вызовы для работы с файлами, сокетами и т. Д. c. были сделаны асинхронно c -дружелюбными. (Спасибо @JimB за напоминание мне об этом и авторам полезных связанных ответов.)

...