go 架构根据内置的并发原语提供强大的并行编程作用,包含 goroutine(轻量进程)、channel(通讯)和锁。这些特性使程序员可以明确且快速地撰写并行编码,同时提高效率和扩展性。
Go 架构在并行编程上的优势
并发编程在当代APP开发中尤为重要,它允许同时执行多个任务以提高效率。Go 凭借内置的并发售词义,为并行编程提供了强大而易用的特点。
内置的并发原语
Go 关键库提供了一系列并发原语,包含 goroutine(轻量进程)、channel(用以通讯)和锁。这种原语容许程序猿明确和快速地撰写并行编码。
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
fmt.Printf("goroutine %d: sleeping for 1 second ", i)
time.Sleep(1 time.Second)
wg.Done()
}(i)
}
wg.Wait() // 等候全部 goroutine 进行
}
这段代码创立了 10 个 goroutine,每个 goroutine 睡眠 1 秒,然后向主线程发出信号表明已完成。WaitGroup 确保所有 goroutine 完成后再执行。
Channel用以通讯
Channel是Go 中用于 goroutine 中间通信的安全并发的值缓冲区。他们容许程序猿以同歩或异步方式无堵塞地发送和接收数据。
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
ch := make(chan int)
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 10; i++ {
ch <- i
}
close(ch) // 关掉 channel 以标示数据发送结束
}()
wg.Add(1)
go func() {
defer wg.Done()
for v := range ch {
fmt.Printf("received value: %d ", v)
}
}()
wg.Wait() // 等候全部 goroutine 进行
}
在这个例子中,goroutine 在 channel 上推送值,而另一个 goroutine 从 channel 接受值。close() 函数用以通告接受者 channel 已关闭,不会再有数据发送。
实战案例 :并行图像处理
Go 在并行计算大批数据时非常高效。下面是一个应用Go 并行计算图像的实例:
import (
"image"
"image/jpeg"
"os"
"sync"
)
func main() {
// 开启文件列表
files, err := os.ReadDir("images")
if err != nil {
panic(err)
}
// 创建一个用于处理图像的 goroutine 池
const numWorkers = 4
pool := make(chan image.Image, numWorkers)
var wg sync.WaitGroup
for _, file := range files {
wg.Add(1)
go func(file string) {
// 开启图象并调整大小
img, err := os.Open("images/" + file)
if err != nil {
panic(err)
}
resizedImg, err := resizeImage(img)
if err != nil {
panic(err)
}
pool <- resizedImg // 将调整大小后的图象放进 channel
wg.Done()
}(file.Name())
}
go func() {
for img := range pool {
// 储存调整大小后的图象
err := saveImageAsJPEG(img, "resized-images/"+file.Name())
if err != nil {
panic(err)
}
}
}()
wg.Wait() // 等候全部 goroutine 进行
}
func resizeImage(r io.Reader) (resizedImg image.Image, err error) {
// 先把文档分析为图像数据
img, err := jpeg.Decode(r)
if err != nil {
return nil, err
}
// 调节图像大小
resizedImg=image.NewRGBA(image.Rect(0,0,img.Bounds().Dx()/2,img.Bounds().Dy()/2))
fory:=0;y
forx:=0;x
p:=yresizedImg.Bounds().Dy()+x
resizedImg.Pix[p4]=img.Pix[(2y+1)img.Bounds().Dx()+(2x+1)4]
resizedImg.Pix[p4+1]=img.Pix[(2y+1)img.Bounds().Dx()+(2x+1)4+1]
resizedImg.Pix[p4+2]=img.Pix[(2y+1)img.Bounds().Dx()+(2x+1)4+2]
resizedImg.Pix[p4+3]=img.Pix[(2y+1)img.Bounds().Dx()+(2x+1)4+3]
}
}
returnresizedImg,nil
}
funcsaveImageAsJPEG(imgimage.Image,fstring)error{
file,err:=os.Create(f)
iferr!=nil{
returnerr
}
err=jpeg.Encode(file,img,&jpeg.Options{
Quality:95,
})
returnerr
}
这一编码应用 goroutine 池并行计算键入目录中的图象。它首先开启图像文件,调节其大小,再将调整大小后的图象放进 channel。另一个 goroutine 从 channel 中载入图象并把它保存到新目录中。
以上就是golang架构在并行编程上的优势体现在哪里?的详细内容,大量请关注其他类似文章!