2014-08-28 3 views
6

Я следил за Go Tour, и я немного застреваю, когда речь заходит о гортанах. Я понимаю, что они очень легкие, и что каждый раз, когда goroutine блоки, еще один будет начать, но я не могу получить мою голову вокруг, как на самом деле работает этот пример:Как работают goroutines?

package main 

import (
    "fmt" 
    "time" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     time.Sleep(1000 * time.Millisecond) 
     fmt.Println(s) 
    } 
} 

func main() { 
    go say("world") 
    say("hello") 
} 

Playground

Я понимаю, что goroutine запускается для функции say с аргументом «мир», но насколько я понимаю, это должно печатать «мир» пять раз и «привет» один раз. Однако я не понимаю, почему выход, как это:

hello 
world 
hello 
world 
hello 
world 
hello 
world 
hello 

Из моего ограниченного понимания потоков из других языков, на выходе должно быть что-то вроде этого:

hello 
world 
world 
world 
world 
world 

или как это:

world 
world 
world 
hello 
world 
world 

Почему вторая строка выполняется пять раз? Делает ли что-либо под оператором go классифицировать как часть процедуры go?

Также на следующий слайд-шоу что-то я не могу получить мою голову раунд снова:

package main 

import "fmt" 

func sum(a []int, c chan int) { 
    sum := 0 
    for _, v := range a { 
     sum += v 
    } 
    c <- sum // send sum to c 
} 

func main() { 
    a := []int{7, 2, 8, -9, 4, 0} 

    c := make(chan int) 
    go sum(a[:len(a)/2], c) 
    go sum(a[len(a)/2:], c) 
    x, y := <-c, <-c // receive from c 

    fmt.Println(x, y, x+y) 
} 

Playground

goroutine начинается во второй половине среза, а затем еще один для первого часть среза, однако значениям x и y присвоены два разных значения. Как я вижу, функция sum отправит ее сумму на канал c, а затем следующий sum отправит сумму на тот же канал c, так как двум переменным могут присваиваться два разных значения? Должен ли канал c иметь одно значение sum?

Я ценю, что это довольно длинный вопрос, но я не смог найти ответ на эти вопросы.

ответ

6

Почему вторая строка выполняется в 5 раз?

Вторая строка будет печатать hello каждую секунду 5 раз в потоке main().
Но одновременно первая строка go say("world") также будет печатать мир каждые пять секунд в отдельной горутине.
Sleep гарантирует, что каждая рутина дает, позволяя другому возобновиться.

Отсюда вывод:

hello 
world 
hello 
world 
hello 
world 
hello 
world 
hello 

Как я вижу, что функция сумма будет посылать это сумма к каналу с, а затем следующая сумма будет посылать это сумма на тот же канал с таким как двум переменным присваиваются два разных значения?

Потому что каждая отправка будет блокироваться на c до тех пор, пока не будет прочитан канал c.
Поскольку существуют две записи в c, вам нужно прочитать:

x, y := <-c, <-c // receive from c twice. 

Assignement section of Golang Spec позволяет для назначения кортежа, если:

число операндов слева должно равняться числу выражений справа, каждый из которых должен быть однозначным, а выражение nth справа присваивается n-му операнду слева.

+0

Ох. Кажется, я понял. Главное - это обычная рутина, как вы сказали. Привет будет напечатан, потому что главный блокируется сна в рутине. Поскольку всякий раз, когда процедура блокируется, новый запускает основные повторы 5 раз, но в то же время функция повторяется и 5 раз. Привет сначала печатается, потому что код перескакивает по процедуре, ожидая его сна. – Bula

+0

Также это еще один вопрос относительно моего второго примера. Скажем, есть миллионы вызовов функций суммы с приходом к нему. Если программа не попадает в строку, которая блокирует программу до того, как сумма закончит вычисление, это значение будет потеряно правильно? – Bula

+0

@ Була извините за запоздалый ответ. Да, main() является goroutine сам по себе и будет работать на 'Sleep()'. – VonC

1

Для первой функции вы должны увидеть значения в представленном стиле VonC. Причина hello печатает 5 раз, потому что функция say печатает вещи 5 раз. Представьте себе программу без горутин. Я думаю, что это не гарантирует, что вы получите hello и world отлично перемешаны, но я могу ошибаться.

Причина канал работает в:

  1. Golang давайте вы множественное присваивание, как VonC упоминает
  2. Каналы empty out, то есть, когда вы назначаете c к x он удаляет первую сумму, которая была передана в канал и когда он назначает c на y, он переходит во второе значение (опять же я думаю, что заказ не является гарантией, так как x может иметь первую половину и y вторую половину суммы или наоборот.

Если вы представляете каналы как своего рода очереди, я думаю, что это имеет больше смысла. Суммирующие goroutines вставляют значения в очередь, и присваивания последовательно выставляют значения.

Смежные вопросы