Go语言多核并行化


本站和网页 http://c.biancheng.net/view/4362.html 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

Go语言多核并行化
首页
教程
VIP会员
一对一答疑
辅导班
公众号
首页
C语言教程
C++教程
Python教程
Java教程
Linux入门
更多>>
目录
Go语言
Go语言简介
Go语言基本语法
Go语言容器
流程控制
Go语言函数
Go语言结构体
Go语言接口
Go语言包(package)
9 Go语言并发 9.1 Go语言并发简述9.2 Go语言轻量级线程9.3 Go语言并发通信9.4 Go语言竞争状态9.5 Go语言调整并发的运行性能9.6 并发和并行的区别9.7 goroutine和coroutine的区别9.8 Go语言通道(chan)9.9 示例:并发打印9.10 Go语言单向通道9.11 Go语言无缓冲的通道9.12 Go语言带缓冲的通道9.13 Go语言channel超时机制9.14 Go语言通道的多路复用9.15 Go语言模拟远程过程调用9.16 示例:使用通道响应计时器的事件9.17 Go语言关闭通道后继续使用通道9.18 Go语言多核并行化9.19 Go语言Telnet回音服务器9.20 检测代码在并发环境下可能出现的问题9.21 互斥锁和读写互斥锁9.22 Go语言等待组9.23 死锁、活锁和饥饿概述9.24 示例:封装qsort快速排序函数9.25 Go语言CSP:通信顺序进程简述9.26 示例:聊天服务器9.27 高效地使用Go语言并发特性9.28 使用select切换协程9.29 Go语言加密通信
10
Go语言反射
11
Go语言文件处理
12
Go语言编译与工具
首页 > Go语言 > Go语言并发
Go语言多核并行化
Go语言具有支持高并发的特性,可以很方便地实现多线程运算,充分利用多核心 cpu 的性能。
众所周知服务器的处理器大都是单核频率较低而核心数较多,对于支持高并发的程序语言,可以充分利用服务器的多核优势,从而降低单核压力,减少性能浪费。
Go语言实现多核多线程并发运行是非常方便的,下面举个例子:
package main
import (
"fmt"
func main() {
for i := 0; i < 5; i++ {
go AsyncFunc(i)
func AsyncFunc(index int) {
sum := 0
for i := 0; i < 10000; i++ {
sum += 1
fmt.Printf("线程%d, sum为:%d\n", index, sum)
运行结果如下:
线程0, sum为:10000
线程2, sum为:10000
线程3, sum为:10000
线程1, sum为:10000
线程4, sum为:10000
在执行一些昂贵的计算任务时,我们希望能够尽量利用现代服务器普遍具备的多核特性来尽量将任务并行化,从而达到降低总计算时间的目的。此时我们需要了解 CPU 核心的数量,并针对性地分解计算任务到多个 goroutine 中去并行运行。
下面我们来模拟一个完全可以并行的计算任务:计算 N 个整型数的总和。我们可以将所有整型数分成 M 份,M 即 CPU 的个数。让每个 CPU 开始计算分给它的那份计算任务,最后将每个 CPU 的计算结果再做一次累加,这样就可以得到所有 N 个整型数的总和:
type Vector []float64
// 分配给每个CPU的计算任务
func (v Vector) DoSome(i, n int, u Vector, c chan int) {
for ; i < n; i++ {
v[i] += u.Op(v[i])
c <- 1 // 发信号告诉任务管理者我已经计算完成了
const NCPU = 16 // 假设总共有16核
func (v Vector) DoAll(u Vector) {
c := make(chan int, NCPU) // 用于接收每个CPU的任务完成信号
for i := 0; i < NCPU; i++ {
go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c)
// 等待所有CPU的任务完成
for i := 0; i < NCPU; i++ {
<-c // 获取到一个数据,表示一个CPU计算完成了
// 到这里表示所有计算已经结束
这两个函数看起来设计非常合理,其中 DoAll() 会根据 CPU 核心的数目对任务进行分割,然后开辟多个 goroutine 来并行执行这些计算任务。
是否可以将总的计算时间降到接近原来的 1/N 呢?答案是不一定。如果掐秒表,会发现总的执行时间没有明显缩短。再去观察 CPU 运行状态,你会发现尽管我们有 16 个 CPU 核心,但在计算过程中其实只有一个 CPU 核心处于繁忙状态,这是会让很多Go语言初学者迷惑的问题。
官方给出的答案是,这是当前版本的 Go 编译器还不能很智能地去发现和利用多核的优势。虽然我们确实创建了多个 goroutine,并且从运行状态看这些 goroutine 也都在并行运行,但实际上所有这些 goroutine 都运行在同一个 CPU 核心上,在一个 goroutine 得到时间片执行的时候,其他 goroutine 都会处于等待状态。从这一点可以看出,虽然 goroutine 简化了我们写并行代码的过程,但实际上整体运行效率并不真正高于单线程程序。
虽然Go语言还不能很好的利用多核心的优势,我们可以先通过设置环境变量 GOMAXPROCS 的值来控制使用多少个 CPU 核心。具体操作方法是通过直接设置环境变量 GOMAXPROCS 的值,或者在代码中启动 goroutine 之前先调用以下这个语句以设置使用 16 个 CPU 核心:
runtime.GOMAXPROCS(16)
到底应该设置多少个 CPU 核心呢,其实 runtime 包中还提供了另外一个 NumCPU() 函数来获取核心数,示例代码如下:
package main
import (
"fmt"
"runtime"
func main() {
cpuNum := runtime.NumCPU() //获得当前设备的cpu核心数
fmt.Println("cpu核心数:", cpuNum)
runtime.GOMAXPROCS(cpuNum) //设置需要用到的cpu数量
运行结果如下:
cpu核心数: 4
关注公众号「站长严长生」,在手机上阅读所有教程,随时随地都能学习。本公众号由C语言中文网站长亲自运营,长期更新,坚持原创。
微信扫码关注公众号
优秀文章
C++默认参数(函数参数的默认值)
Linux Vim三种工作模式(命令模式、输入模式和编辑模式)详解
Java Integer类详解
Linux at命令详解:定时执行任务
Python类对象的创建和使用
JS every()方法:检测数组元素是否全部符合指定条件
Java中为什么使用向上转型而不直接创建子类对象?
MySQL查看视图
Django项目创建第一个应用
MyBatis一对一关联查询
精美而实用的网站,分享优质编程教程,帮助有志青年。千锤百炼,只为大作;精益求精,处处斟酌;这种教程,看一眼就倾心。
关于网站 |
关于站长 |
如何完成一部教程 |
公众号 |
联系我们 |
网站地图
Copyright ©2012-2022 biancheng.net, 冀ICP备2022013920号, 冀公网安备13110202001352号
加入微信交流群,一起学习不枯燥。内含一款搜索神器,免费下载全网书籍和视频。