24. Понимание сопрограмм в Go: горутины

Go

Привет всем, меня зовут Мин.

В период самостоятельного изучения Golang я написал подробные учебные заметки и разместил их в своем личном общедоступном аккаунте WeChat «Время программирования на Go».Что касается языка Go, я тоже новичок, поэтому то, что я написал, должно больше подходить для новых студентов, если вы только изучаете язык Go, вам стоит обратить на него внимание, учиться и расти вместе.

Мой онлайн-блог:golang.iswbm.comМой Github: github.com/iswbm/GolangCodingTime


Когда дело доходит до языка Go, у многих людей, которые не сталкивались с ним, должно быть первое впечатление, что он поддерживает параллелизм на уровне языка, что очень удобно, позволяя разработчикам быстро писать высокопроизводительные и простые для понимания программы.

В Python (например, в Py, в основном потому, что я знаком с другими основными языками программирования) порог параллельного программирования не низок, вам нужно изучить многопроцессорность, многопоточность и освоить asyncio, библиотеку, поддерживающую параллелизм. ., aiohttp и т. д. В то же время вы также должны четко понимать различия, преимущества и недостатки между ними и знать, как выбирать разные режимы параллелизма в разных сценариях.

И Golang, как современный язык программирования, не требует, чтобы вы сталкивались с этими сложными проблемами лицом к лицу. В Golang вам не нужно учиться создавать пулы процессов/пулов потоков, и вам не нужно знать, когда использовать многопоточность и когда использовать многопроцессорность. Поскольку вам не нужно выбирать, и вам не нужно выбирать, горутина (то есть сопрограмма), которую она предоставляет изначально, достаточно хороша, чтобы автоматически обрабатывать все за вас, и все, что вам нужно сделать, это выполнить ее. , это так просто.

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

// 执行一个函数
func()

// 开启一个协程执行这个函数
go func()

1. Первоначальное использование сопрограмм

Вход в программу Go обычно является основной функцией.После запуска программы сначала запускается основная функция, которую мы называемmain goroutine.

Его можно использовать только в основном или в коде, вызываемом под нимgo + func()способ запуска сопрограммы.

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

Поэтому следующий код работает, только выводhello, world, вместо выводаhello, go(Поскольку создание сопрограмм требует времени, когдаhello, worldПосле печати сопрограмма не успела выполниться)

import "fmt"

func mytest() {
    fmt.Println("hello, go")
}

func main() {
    // 启动一个协程
    go mytest()
    fmt.Println("hello, world")
}

Для изучающих сопрограммы, которые только изучают Go, вы можете использовать time.Sleep, чтобы заблокировать main, чтобы другие сопрограммы могли работать полностью, но вы должны отметить, что это не рекомендуемый способ (позже мы изучим другие методы, более элегантный способ). ).

Когда я добавляю строку time.Sleep в код, результат соответствует ожидаемому.

import (
    "fmt"
    "time"
)

func mytest() {
    fmt.Println("hello, go")
}

func main() {
    go mytest()
    fmt.Println("hello, world")
    time.Sleep(time.Second)
}

Вывод выглядит следующим образом

hello, world
hello, go

2. Эффект нескольких сопрограмм

Чтобы вы могли увидеть эффект параллелизма, вот самый простой пример

import (
    "fmt"
    "time"
)

func mygo(name string) {
    for i := 0; i < 10; i++ {
        fmt.Printf("In goroutine %s\n", name)
        // 为了避免第一个协程执行过快,观察不到并发的效果,加个休眠
        time.Sleep(10 * time.Millisecond) 
    }
}

func main() {
    go mygo("协程1号") // 第一个协程
    go mygo("协程2号") // 第二个协程
    time.Sleep(time.Second)
}

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

In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程1号
In goroutine 协程2号
In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程1号
In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程2号
In goroutine 协程1号
In goroutine 协程2号

Благодаря приведенному выше простому примеру вы убедились в мощной функции параллелизма Go и преобразовали синхронный код в асинхронный код, вам действительно нужно только одно ключевое слово, и вам не нужно использовать другие библиотеки, что просто и удобно.

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

Руководство по серии

01. Построение среды разработки (Goland & VS Code)

02. Изучите пять методов создания переменных

03. Подробные типы данных:**Целое число и число с плавающей запятой**

04. Подробные типы данных: байт, руна и строка

05. Подробно объясните типы данных: массивы и срезы

06. Подробно объясните типы данных: словари и логические значения

07. Подробно объясните типы данных: указатели

08. Объектно-ориентированное программирование: структуры и наследование

09. Статья для понимания функций в Go

10. Управление потоком языка Go: условный оператор if-else

11. Управление потоком языка Go: оператор выбора switch-case

12. Управление потоком языка Go: оператор цикла for

13. Перейти к управлению языковым потоком: перейти к безусловному переходу

14. Перейти к управлению языковым потоком: отложить отложенный вызов

15. Объектно-ориентированное программирование: интерфейсы и полиморфизм

16. Ключевые слова: В чем разница между make и new?

17. Статья о понимании блоков и области видимости в Go

18. Изучите Go Coroutines: горутины

19. Изучите сопрограммы Go: подробно объясните каналы/каналы

20. Подробное объяснение нескольких классических случаев ошибки взаимоблокировки канала.

21. Изучите сопрограммы Go: группа ожидания

22. Изучите процедуры Go: мьютексы и блокировки чтения-записи

23. Обработка исключений в Go: паника и восстановление

24. Сверхдетальная интерпретация прошлой жизни Go Modules и вводное использование

25. 8 важных знаний об импорте пакетов на языке Go

26. Как открыть исходный код модулей, которые я написал для использования другими?

27. Расскажите об утверждениях типов в Go?

28. Эти пять пунктов помогут вам понять, как использовать select в языке Go.