Golang入坑总结-中篇

众所周知,当我们要实现一个高并发的服务,要应对大流量时代带来的服务器的压力,必须从程序的角度上完成一个近乎完美的并发编程,相信我,Go将是各位的不二之选!
下面就闲谝以下Go语言如何实现并发!

并发

针对部分刚刚入坑的小白来说,有必要阐述以下并发并行的区别,在计算机领域,这是两个非常重要的概念。简单地说:并发是多个事情在一个物理处理器上运行,轮询执行,实现多个事情同时做的错觉;而并行,则针对那些物理处理器多的设备,实现多个事情真的是同一时间在执行!

线程

线程是一个执行空间,这个执行空间会被操作系统调度器选择运行其中的代码片段,不同的操作系统使用的线程的调度算法都不一样,不过这不是我们所关心的。

进程

进程是操作系统进行资源分配的基本单位,维护了应用程序运行时的内存地址空间,设备和文件的句柄以及线程

Goroutine

区别于其他语言,操作系统会在物理处理器上调度线程来运行,而Go语言会在逻辑处理器上调度goroutine来运行,每个逻辑处理器会分别绑定单个操作系统线程
线程,逻辑处理器,goroutine之间的关系可以使用下图描述
如何运行goroutine
下面简单的创建goroutine实现并发编程

package main

import (
	"fmt"
	"runtime"
	"sync"
)

func main() {
	// 指定逻辑处理器的数量为1
	runtime.GOMAXPROCS(1)
	// 创建一个变量wg,等待程序执行完成
	var wg sync.WaitGroup
	// 此处代表主线程需要等待goroutine执行完成
	wg.Add(2)
	// 声明一个匿名函数,创建一个goroutine1
	go func() {
		defer wg.Done() // 函数执行完成时调用Done函数告诉main函数我的工作已经完成
		for i := 0; i < 10; i++{
			fmt.Println(i)
		}
	}()
	// 声明一个匿名函数,创建一个goroutine2
	go func() {
		defer wg.Done()
		for i := 'a'; i < 'a'+26; i++{
			fmt.Println(i)
		}
	}()
	// 等待两个g执行结束
	wg.Wait()
}

可以看出,go语言实现并发就是这么easy!

竞争状态与锁住共享资源

接触过其他语言的童鞋都知道,一提到并发,一提到线程,总避免不了互相访问共享资源带来的各种问题,在Python里面我们讲线程是非安全的,需要加以各种机制,在Go语言里面,提出了竞争状态这个概念
何为竞争状态?当两个或多个goroutine在没有互相同步的前提下,访问某个共享资源,并试图同时去读写这个资源,就会产生竞争状态,当然这种状态是我们不想看到的
Go给我们提供了竞争检测器,如何使用呢?只需go build -race,竞争检测器就会向我们指出当前程序哪里存在潜在问题
在没有接触通道这个概念之前,其他语言总是会使用锁的机制来限制这种共享资源带来的安全问题,同样地,Go语言也提供了传统的锁机制
目前锁住共享资源存在以下几种解决策略

  • 使用原子函数,原子函数会将调用互相同步,保证同一时间只有一个操作修改共享资源;
  • 使用互斥锁,这个概念基本上每种语言都会去支持,简单的讲,其思想就是在代码上创建一个临界区,保证同一时间只能有一个goroutine去执行这个临界区的代码,请看代码片段
package main
import (
	"sync"
)

var (
	inst int
	wg sync.WaitGroup
	// 用来定义一段代码隔离区
	mutex sync.Mutex
)
func main() {
	wg.Add(2)
	go addInst(1)
	go addInst(2)
	wg.Wait()
}

func addInst(id int) {
	defer wg.Done()
	for i:=0;i<10;i++{
		mutex.Lock()
		{
			num := inst
			num++
			inst = value
		}
		mutex.Unlock()
	}
}
通道

好吧,上面说的那些同步机制只是个开胃菜,对于Go语言来说,主菜是通道,这种通道机制无疑给goroutine插上了梦的翅膀,使得Go语言的并发性能扶摇九万里
当一个资源需要在goroutine之间共享时,通道的引入给各个goroutine之间开辟了一个管道,这个管道分为有缓冲以及无缓冲两种模式
下面简单声明一个通道

// 创建一个无缓冲的通道
unbuffered = make(chan int)
// 创建一个有缓冲的通道,包含10个值
buffered = make(chan int, 10)

无缓冲的通道与有缓冲的通道有何差别?相信看了以下的图解就会一目了然
无缓冲通道工作模式
有缓冲通道工作模式
无缓冲通道:
指在接收之前没有能力保存任何值,这就要求两个goroutine,作为发送方以及接收方,其动作必须一致,同步化,才可完成通道资源的发送与接收,否则会出现一方阻塞的情况,可以模拟两个人打网球的场景;
有缓冲通道:
指在未接收之前可以存储一个或者多个值的通道,并不强制要求发送方与接收方动作同步,只有在通道中没有要接收的值时,接收动作才会阻塞;在通道没有可用缓冲区存储资源时,发送动作才会阻塞,可以想象一个资源池的场景,很多资源需要被多个 goroutine去完成,可以使用有缓冲的通道实现;
通道关闭后,接收方仍可以从其中获取数据,保证数据不会丢失!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值