可以近乎无限开启的线程。在 Go 语言中被称之为 goroutine ,它是线程的轻量级实现。
在 Go 语言中使用 go 关键字来创建 goroutine ,形如go 函数名()的形式去创建。每一个 goroutine 必须是一个函数,这个函数也可以是匿名函数。
package main
import (
"fmt"
"time"
)
func print0to10() {
for i := 0; i <= 10; i++ {
fmt.Println("print0to10:", i)
time.Sleep(time.Microsecond)
}
}
func main() {
go print0to10()
go func() {
for i := 'A'; i <= 'K'; i++ {
fmt.Println("printAtoK:", string(i))
time.Sleep(time.Microsecond)
}
}()
time.Sleep(time.Second)
}
print0to10: 0
print0to10: 1
printAtoK: A
print0to10: 2
printAtoK: B
printAtoK: C
printAtoK: D
print0to10: 3
print0to10: 4
printAtoK: E
print0to10: 5
printAtoK: F
printAtoK: G
printAtoK: H
print0to10: 6
printAtoK: I
print0to10: 7
printAtoK: J
print0to10: 8
printAtoK: K
print0to10: 9
print0to10: 10
其它语言并发时进程中的通讯一般都是通过共享内存(全局变量)的方式来实现的,这样一来各个模块之间的耦合会变得非常紧密。所以后来提出了使用通讯来共享内存这一概念,来解耦合。在 Go 语言中就是使用 channel 的方式来达到这一目的的。
package main
import (
"fmt"
"time"
)
var c1 chan rune = make(chan rune, 0)
var c2 chan int = make(chan int, 0)
func print0to10() {
for i := 'A'; i <= 'K'; i++ {
num := <-c2
fmt.Println("print0to10:", num)
c1 <- i
}
}
func main() {
go print0to10()
go func() {
c2 <- 0
for i := 1; i <= 11; i++ {
char := <-c1
fmt.Println("printAtoK:", string(char))
c2 <- i
}
}()
time.Sleep(time.Second)
}
print0to10: 0
printAtoK: A
print0to10: 1
printAtoK: B
print0to10: 2
printAtoK: C
print0to10: 3
printAtoK: D
print0to10: 4
printAtoK: E
print0to10: 5
printAtoK: F
print0to10: 6
printAtoK: G
print0to10: 7
printAtoK: H
print0to10: 8
printAtoK: I
print0to10: 9
printAtoK: J
print0to10: 10
printAtoK: K
线程不安全的 map 。之所以线程不安全是因为其内部实现机制中无法同时读写,若有两个 goroutine 一个在读取 map 中的值,而另一个在更新 map 中的值,就会导致程序崩溃。
package main
import (
"fmt"
"time"
)
func main() {
m := map[string]int{"A": 1, "B": 2, "C": 3, "D": 1, "E": 2, "F": 3}
for i := 0; i < 100; i++ {
go func() {
for v := range m {
m[v] = 100
}
}()
}
time.Sleep(time.Second)
fmt.Println(m)
}
fatal error: concurrent map writes
这个就是线程不安全的 map 不建议使用的原因,除了直接使用线程安全的 map 之外,还可以为这些 goruntine 加上锁,使其无法同时对 map 进行读写操作,这样也可以保障各线程的安全。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var lock sync.Mutex
m := map[string]int{"A": 1, "B": 2, "C": 3, "D": 1, "E": 2, "F": 3}
for i := 0; i < 100; i++ {
go func() {
lock.Lock()
for v := range m {
m[v] = 100
}
lock.Unlock()
}()
}
time.Sleep(time.Second)
fmt.Println(m)
}
map[A:100 B:100 C:100 D:100 E:100 F:100]
goroutine 执行无先后顺序,由 cpu 统一调度。
goroutine 之间内存的共享通过使用 channel 来通讯实现。
goroutine 使用线程不安全的变量类型时可以用锁将其锁定。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。