Автор: Линь Гуаньхун / Призраки под рукой
Самородки:Талант /user/178526…
Гитхаб:GitHub.com/afan913337456…
Облачная колонка Tencent:cloud.Tencent.com/developer/U…
содержание
- предисловие
- сопрограмма
- Особенности сопрограмм
-
第 1
и第 2
точка - Пункты 3 и 4 в характеристиках
-
- Общее сравнение с потоками
предисловие
Всех с Национальным праздником, прошло почти два месяца с момента последнего поста, а 19 лет подходят к концу. Теперь резюме больше на草稿
Вместо того, чтобы отправлять его, на этот раз я подробно поделюсь им в Go.线程和协程的区别及其关系
.
сопрограмма
Корутина, английское имяCoroutine
. Но на языке Go английское название сопрограммы:gorutine
. это часто используется для多任务
,Сейчас并发作业
. Верно多线程
Работа работы.
Хотя в Go нам не нужно писать код, такой как потоки, непосредственно для параллелизма, но сопрограммы Go依赖于线程
продолжать.
Давайте посмотрим на их различия ниже.
Чтобы ознакомиться с основами работы с потоками, поищите статьи в Интернете, потому что уже есть много отличных вводных статей о потоках.
Особенности сопрограмм
Здесь характеристики потока перечислены непосредственно, а затем проанализированы на примере.
- Несколько сопрограмм могут управляться одним или несколькими потоками.
协程的调度
происходит в своем собственном потоке. - Его можно запланировать, и стратегия планирования определяется кодом прикладного уровня, который можно настраивать в широких пределах.
- Высокая эффективность исполнения.
- Занимайте меньше памяти.
выше第 1
и第 2
точка
Давайте посмотрим на пример:
func TestGorutine(t *testing.T) {
runtime.GOMAXPROCS(1) // 指定最大 P 为 1,从而管理协程最多的线程为 1 个
wg := sync.WaitGroup{} // 控制等待所有协程都执行完再退出程序
wg.Add(2)
// 运行一个协程
go func() {
fmt.Println(1)
fmt.Println(2)
fmt.Println(3)
wg.Done()
}()
// 运行第二个协程
go func() {
fmt.Println(65)
fmt.Println(66)
// 设置个睡眠,让该协程执行超时而被挂起,引起超时调度
time.Sleep(time.Second)
fmt.Println(67)
wg.Done()
}()
wg.Wait()
}
Приведенный выше фрагмент кода запускает две сопрограммы.После запуска наблюдайте за выводом顺序是交错
из. может быть:
65
66
1
2
3
67
Это означает, что в процессе выполнения сопрограммы А вы можете随时中断
, чтобы выполнить строку сопрограммы B, сопрограмма B также может быть прервана в процессе выполнения, а затем выполнена сопрограмма A.
Кажется, что выполнение сопрограммы A и сопрограммы B похоже на переключение потоков, но обратите внимание, что и A, и B здесь выполняются в одном потоке. Их планирование — это не переключение потоков, а纯应用态的协程调度
.
Что касается приведенного выше кода, зачем указывать следующие две строки кода?
runtime.GOMAXPROCS(1)
time.Sleep(time.Second)
Для этого вам нужно ознакомиться с основами планирования сопрограмм Go. См. мою предыдущую статью об анализе планирования:
Механизм планирования сопрограмм Go
Если не установленоruntime.GOMAXPROCS(1)
, то программа запустит соответствующее количество P согласно количеству ядер процессора операционной системы, в результате чего получится несколько M, то есть запуск потоков. Тогда сопрограмма в нашей программе будет分配到不同的线程
вошел внутрь. Для демонстрации число установлено равным 1, так что все они выделены одному и тому же потоку, сохранены в очереди сопрограммы потока, ожидая выполнения или планирования.
Пункты 3 и 4 в Coroutine Features.
- Высокая эффективность исполнения.
- Занимайте меньше памяти.
так как协程的调度切换不是线程切换
, а управляется самой программой, так что,没有线程切换的开销
, По сравнению с многопоточностью, чем больше потоков, тем очевиднее преимущество сопрограмм в производительности. Планирование происходит в режиме приложения, а не в режиме ядра.
Стоимость памяти, использующая память потока, в котором она находится, означает, что память потока может использоваться несколькими сопрограммами.
Планирование второй сопрограммы不需要多线程的锁机制
, так как есть только один поток, также不存在同时写变量冲突
, поэтому эффективность выполнения намного выше, чем при многопоточности.
Общее сравнение с потоками
точка сравнения | нить | сопрограмма |
---|---|---|
хранилище данных | Пространство памяти в режиме ядра | Как правило, это пространство памяти пользовательского режима, предоставляемое потоком. |
переключить действие | Операция, наконец, завершается на уровне ядра, и уровень приложения должен вызвать базовую функцию системного вызова, предоставляемую уровнем ядра. | Прикладной уровень использует код для простого сохранения и восстановления на месте. |
планирование задач | Реализуется ядром, упреждающий метод, опирающийся на различные блокировки | Это осуществляется специальным планировщиком реализации пользовательского режима. Например, планировщик для go coroutines |
уровень голосовой поддержки | большинство языков программирования | Некоторые языки: Lua, Go, Python... |
Спецификация реализации | Реализовано в соответствии с современными спецификациями операционной системы | Единой спецификации нет. Он реализован разработчиками на уровне приложения и имеет широкие возможности настройки, например, поддерживает только однопоточные потоки. различные стратегии планирования и т. д. |
личная реклама
Опубликована моя техническая книга «Практика разработки блокчейн-приложений на Ethereum», которую можно приобрести в Интернете.