воскресенье, 15 марта 2020 г.

Goroutines - легкие потоки

Оператор go запускает функцию в отдельном потоке выполнения.

Вы можете начать новый поток выполнения, goroutine, с помощью оператора go. Он запускает функцию в другой, недавно созданной goroutine. Все goroutines в одной программе имеют одинаковое адресное пространство.

go list.Sort() // Запустить list.Sort параллельно; не ждите этого.

Следующая программа напечатает "Привет из главной goroutine". Также может быть напечатано "Привет из другой goroutine", в зависимости от того, какая из двух goroutine завершится первой.

func main() {
    go fmt.Println("Привет из другой goroutine")
    fmt.Println("Привет из главной goroutine")

    // На этом этапе выполнение программы останавливается
    // и все активные goroutines убиты.
}

Следующая программа, скорее всего, напечатает "Привет из главной goroutine" и "Привет из другой goroutine". Они могут быть напечатаны в любом порядке. Еще одна возможность заключается в том, что вторая goroutine чрезвычайно медленная и не печатает свое сообщение до завершения программы.

func main() {
    go fmt.Println("Привет из другой goroutine")
    fmt.Println("Привет из главной goroutine")

    // даем время другой goroutine завершиться
    time.Sleep(time.Second) 
}

Вот несколько более реалистичный пример, где мы определяем функцию, которая использует конкурентность для отсрочки события.

// Publish выводит текст на стандартный вывод 
// по истечении заданного времени.
// Она не блокируется, но сразу возвращается.
func Publish(text string, delay time.Duration) {
    go func() {
        time.Sleep(delay)
        fmt.Println("BREAKING NEWS:", text)
    }() // Обратите внимание на круглые скобки. 
        // Мы должны вызвать анонимную функцию.
}

Вот как вы можете использовать функцию Publish.

func main() {
    Publish("goroutine запускается в новом потоке", 5*time.Second)
    fmt.Println("Будем надеяться, что новости будут опубликованы до того как я выйду")

    // Дождаться публикации новостей.
    time.Sleep(10 * time.Second)

    fmt.Println("Десять секунд спустя: я выхожу сейчас")
}

Программа, скорее всего, напечатает эти три строки в указанном порядке и с пятисекундным перерывом между каждой строкой.

$ go run publish1.go
Будем надеяться, что новости будут опубликованы до того как я выйду
BREAKING NEWS: goroutine запускается в новом потоке
Десять секунд спустя: я выхожу сейчас

В общем случае невозможно организовать, чтобы потоки ждали друг друга за счет Sleep. Основным методом синхронизации в Go является использование каналов.

Реализация

Goroutines легки, стоят немного больше, чем выделение стекового пространства. Стеки начинаются с малого и растут, выделяя и освобождая хранилище кучи по мере необходимости.

Внутренние goroutines действуют как сопрограммы (coroutines), которые мультиплексируются между несколькими потоками операционной системы. Если одна goroutine блокирует поток ОС, например, ожидая ввода, другие goroutines в этом потоке будут мигрировать, чтобы продолжить работу.


Читайте также:


Купить gopher

Комментариев нет:

Отправить комментарий