详解Go 并发

golang 天生语言层面支持并发, 非常棒的语言, 有时我们业务开发时, 遇到复杂场景, 需要用于并发, 将多个请求使用协程组完成并发, 当遇到嵌套循环,还存在上下文关系需要改造为并发请求, 将之前的时间复杂度为O(n^2)改为O(n)的时间复杂度, 那是否还能否并时间复杂度进一步降为O(1)呢? 就出现嵌套并发. 具体如何嵌套并发, 如何写. 今天就一步一步分析.

串行执行

  1. 时间复杂度为O(n^2)
  2. 不使用并发
  3. 结果执行时间为 9s
// 串行执行
func SerializeRun() {
	start := time.Now()
	xx := []int{1, 2, 3}
	yy := []int{100, 200, 300}
	for _, x := range xx {
		for _, y := range yy {
			abc(x, y)
		}
	}
	fmt.Printf("串行执行总时间:%s\n", time.Since(start))
}

func abc(x, y int) {
	time.Sleep(time.Second * 1)
	fmt.Printf("x:%d, y:%d\n", x, y)
}

执行结果

x:1, y:100
x:1, y:200
x:1, y:300
x:2, y:100
x:2, y:200
x:2, y:300
x:3, y:100
x:3, y:200
x:3, y:300
串行执行总时间:9.0026338s

单协程组并发

  1. 使用了协程组将O(n^2)降为O(n)
  2. 结果执行时间为 3s
// 单并行执行
func SingleConcurrenceRun() {
	start := time.Now()
	xx := []int{1, 2, 3}
	yy := []int{100, 200, 300}
	for _, x := range xx {
		wgg := sync.WaitGroup{}
		for _, y := range yy {
			wgg.Add(1)
			go func(x, y int) {
				defer wgg.Done()
				abc(x, y)
			}(x, y)
		}
		wgg.Wait()
	}
	fmt.Printf("单并行执行总时间:%s\n", time.Since(start))
}
func abc(x, y int) {
	time.Sleep(time.Second * 1)
	fmt.Printf("x:%d, y:%d\n", x, y)
}

结果

x:1, y:300
x:1, y:200
x:1, y:100
x:2, y:100
x:2, y:200
x:2, y:300
x:3, y:300
x:3, y:100
x:3, y:200
单并行执行总时间:3.0013813s

嵌套并发执行

  1. 使用嵌套协程组执行并发.
  2. 将O(n^2)降到O(1)
  3. 结果执行时间为 1s
// 嵌套执行
func NestConcurrenceRun() {
	xx := []int{1, 2, 3}
	yy := []int{100, 200, 300}
	start := time.Now()
	wgg := sync.WaitGroup{}
	for _, x := range xx {
		wgg.Add(1)
		go func(x int) {
			wg := sync.WaitGroup{}
			for _, y := range yy {
				wg.Add(1)
				go func(x, y int) {
					defer wg.Done()
					abc(x, y)
				}(x, y)
			}
			wg.Wait()
			wgg.Done()
		}(x)
	}
	wgg.Wait()
	fmt.Printf("嵌套并发执行总时间:%s\n", time.Since(start))
}
func abc(x, y int) {
	time.Sleep(time.Second * 1)
	fmt.Printf("x:%d, y:%d\n", x, y)
}

结果

x:1, y:200
x:3, y:300
x:3, y:200
x:1, y:300
x:2, y:200
x:1, y:100
x:2, y:300
x:2, y:100
x:3, y:100
嵌套并发执行总时间:1.0023542s

以上就是详解Go 并发的详细内容,更多关于Go 并发的资料请关注我们其它相关文章!

(0)

相关推荐

  • Django高并发负载均衡实现原理详解

    1 什么是负载均衡? 当一台服务器的性能达到极限时,我们可以使用服务器集群来提高网站的整体性能.那么,在服务器集群中,需要有一台服务器充当调度者的角色,用户的所有请求都会首先由它接收,调度者再根据每台服务器的负载情况将请求分配给某一台后端服务器去处理. 那么在这个过程中,调度者如何合理分配任务,保证所有后端服务器都将性能充分发挥,从而保持服务器集群的整体性能最优,这就是负载均衡问题. 下面详细介绍负载均衡的四种实现方式 2 HTTP重定向实现负载均衡 过程描述 当用户向服务器发起请求时,请求首先

  • django解决订单并发问题【推荐】

    并发处理 在多个用户同时发起对同一个商品的下单请求时,先查询商品库存,再修改商品库存,会出现资源竞争问题,导致库存的最终结果出现异常. 解决办法: 悲观锁 当查询某条记录时,即让数据库为该记录加锁,锁住记录后别人无法操作,使用类似如下语法 select stock from tb_sku where id=1 for update; SKU.objects.select_for_update().get(id=1) 悲观锁类似于我们在多线程资源竞争时添加的互斥锁,容易出现死锁现象,采用不多. 乐

  • 一百行Golang代码实现简单并发聊天室

    项目介绍:Golang100行代码实现高并发聊天室,其中实现的功能有:上下线广播,私聊,用户改名,超时强踢,在线用户检测等 在开始项目前,我们需要理解贯穿这整个项目的两个重要变量,若能理解这两个变量的使用,那么并发聊天室项目会变得手到擒来.第一个是onlinemap全局map,第二个是Message全局channel. 取名为onlinemap的全局map类型为map[string][client],这个全局字典是用来存储当前在此聊天室的用户的,key值是string类型,为用户的ip地址+Po

  • golang并发ping主机的方法

    利用了golang对高并发的良好支持,同目录下将ip每行一个写入pinglist.txt文件即可 其实这个功能用linux一条命令就能搞定: cat pinglist.txt | xargs -P 10 -I {} ping -fc 100 {} package main import ( "bufio" "bytes" "fmt" "io" "io/ioutil" "log" &quo

  • 详解Go多协程并发环境下的错误处理

    引言 在Go语言中,我们通常会用到panic和recover来抛出错误和捕获错误,这一对操作在单协程环境下我们正常用就好了,并不会踩到什么坑.但是在多协程并发环境下,我们常常会碰到以下两个问题.假设我们现在有2个协程,我们叫它们协程A和B好了: 如果协程A发生了panic,协程B是否会因为协程A的panic而挂掉? 如果协程A发生了panic,协程B是否能用recover捕获到协程A的panic? 答案分别是:会.不能. 那么下面我们来一一验证,并给出在具体的业务场景下的最佳实践. 问题一 如果

  • golang并发下载多个文件的方法

    背景说明 假设有一个分布式文件系统,现需要从该系统中并发下载一部分文件到本地机器. 已知该文件系统的部分节点ip, 以及需要下载的文件fileID列表,并能通过这些信息来拼接下载地址. 其中节点ip列表保存在xx_node.txt, 要下载的fileID保存在xx_fileID.txt中. 代码示例 package main import ( "bufio" "flag" "fmt" "io" "math/rand&

  • Go并发调用的超时处理的方法

    之前有聊过 golang 的协程,我发觉似乎还很理论,特别是在并发安全上,所以特结合网上的一些例子,来试验下go routine中 的 channel, select, context 的妙用. 场景-微服务调用 我们用 gin(一个web框架) 作为处理请求的工具,需求是这样的: 一个请求 X 会去并行调用 A, B, C 三个方法,并把三个方法返回的结果加起来作为 X 请求的 Response. 但是我们这个 Response 是有时间要求的(不能超过3秒的响应时间),可能 A, B, C

  • golang并发编程的实现

    go main函数的执行本身就是一个协程,当使用go关键字的时候,就会创建一个新的协程 channel channel 管道,用于在多个协程之间传递信号 无缓存管道 当对无缓冲通道写的时候,会一直阻塞等到某个协程对这个缓冲通道读 阻塞场景: 通道中无数据,但执行读通道. 通道中无数据,向通道写数据,但无协程读取. 综上,无缓存通道的读写必须同时存在,且读写分别在两个不同的协程 func main(){ ch := make(chan int) go func(ch chan int){ ch <

  • 基于Django的乐观锁与悲观锁解决订单并发问题详解

    前言 订单并发这个问题我想大家都是有一定认识的,这里我说一下我的一些浅见,我会尽可能的让大家了解如何解决这类问题. 在解释如何解决订单并发问题之前,需要先了解一下什么是数据库的事务.(我用的是mysql数据库,这里以mysql为例) 1)     事务概念 一组mysql语句,要么执行,要么全不不执行.  2)  mysql事务隔离级别 Read Committed(读取提交内容) 如果是Django2.0以下的版本,需要去修改到这个隔离级别,不然乐观锁操作时无法读取已经被修改的数据 Repea

  • 详解Go 并发

    golang 天生语言层面支持并发, 非常棒的语言, 有时我们业务开发时, 遇到复杂场景, 需要用于并发, 将多个请求使用协程组完成并发, 当遇到嵌套循环,还存在上下文关系需要改造为并发请求, 将之前的时间复杂度为O(n^2)改为O(n)的时间复杂度, 那是否还能否并时间复杂度进一步降为O(1)呢? 就出现嵌套并发. 具体如何嵌套并发, 如何写. 今天就一步一步分析. 串行执行 时间复杂度为O(n^2) 不使用并发 结果执行时间为 9s // 串行执行 func SerializeRun() {

  • 详解Java并发编程基础之volatile

    目录 一.volatile的定义和实现原理 1.Java并发模型采用的方式 2.volatile的定义 3.volatile的底层实现原理 二.volatile的内存语义 1.volatile的特性 2.volatile写-读建立的happens-before关系 3.volatile的写/读内存语义 三.volatile内存语义的实现 1.volatile重排序规则 2.内存屏障 3.内存屏障示例 四.volatile与死循环问题 五.volatile对于复合操作非原子性问题 一.volati

  • 详解Golang并发操作中常见的死锁情形

    目录 第一种情形:无缓存能力的管道,自己写完自己读 第二种情形:协程来晚了 第三种情形:管道读写时,相互要求对方先读/写 第四种情形:读写锁相互阻塞,形成隐形死锁 什么是死锁,在Go的协程里面死锁通常就是永久阻塞了,你拿着我的东西,要我先给你然后再给我,我拿着你的东西又让你先给我,不然就不给你.我俩都这么想,这事就解决不了了. 第一种情形:无缓存能力的管道,自己写完自己读 先上代码: func main() { ch := make(chan int, 0) ​ ch <- 666 x := <

  • 详解Java并发编程之原子类

    目录 原子数组 AtomicIntegerArray 原子更新器 AtomicIntegerFieldUpdater 原子累加器 LongAdder 原子数组 原子数组有AtomicIntegerArray.AtomicLongArray.AtomicReferenceArray,主要是用来对数组中的某个元素进行原子操作.三个类的方法基本类似,这里只介绍一下AtomicIntegerArray的方法. AtomicIntegerArray 两个构造方法,第一个构造方法传入数组长度初始化一个所有值

  • 详解java并发编程(2) --Synchronized与Volatile区别

    1 Synchronized 在多线程并发中synchronized一直是元老级别的角色.利用synchronized来实现同步具体有一下三种表现形式: 对于普通的同步方法,锁是当前实例对象. 对于静态同步方法,锁是当前类的class对象. 对于同步方法块,锁是synchronized括号里配置的对象. 当一个代码,方法或者类被synchronized修饰以后.当一个线程试图访问同步代码块的时候,它首先必须得到锁,退出或抛出异常的时候必须释放锁.那么这样做有什么好处呢? 它主要确保多个线程在同一

  • 详解python并发获取snmp信息及性能测试

    python & snmp 用python获取snmp信息有多个现成的库可以使用,其中比较常用的是netsnmp和pysnmp两个库.网上有较多的关于两个库的例子. 本文重点在于如何并发的获取snmp的数据,即同时获取多台机器的snmp信息. netsnmp 先说netsnmp.python的netsnmp,其实是来自于net-snmp包. python通过一个c文件调用net-snmp的接口获取数据. 因此,在并发获取多台机器的时候,不能够使用协程获取.因为使用协程,在get数据的时候,协程会

  • 详解Python并发编程之创建多线程的几种方法

    大家好,并发编程 今天开始进入第二篇. 今天的内容会比较基础,主要是为了让新手也能无障碍地阅读,所以还是要再巩固下基础.学完了基础,你们也就能很顺畅地跟着我的思路理解以后的文章. 本文目录 学会使用函数创建多线程 学会使用类创建多线程 多线程:必学函数讲解 经过总结,Python创建多线程主要有如下两种方法: 函数 类 接下来,我们就来揭开多线程的神秘面纱. . 学会使用函数创建多线程 在Python3中,Python提供了一个内置模块 threading.Thread,可以很方便地让我们创建多

  • 详解Python并发编程之从性能角度来初探并发编程

    . 前言 作为进阶系列的一个分支「并发编程」,我觉得这是每个程序员都应该会的. 并发编程 这个系列,我准备了将近一个星期,从知识点梳理,到思考要举哪些例子才能更加让人容易吃透这些知识点.希望呈现出来的效果真能如想象中的那样,对小白也一样的友好. 昨天大致整理了下,这个系列我大概会讲如下内容(后期可能调整): 对于并发编程,Python的实现,总结了一下,大致有如下三种方法: 多线程 多进程 协程(生成器) 在之后的章节里,将陆陆续续地给大家介绍到这三个知识点. . 并发编程的基本概念 在开始讲解

  • 详解Java并发编程之内置锁(synchronized)

    简介 synchronized在JDK5.0的早期版本中是重量级锁,效率很低,但从JDK6.0开始,JDK在关键字synchronized上做了大量的优化,如偏向锁.轻量级锁等,使它的效率有了很大的提升. synchronized的作用是实现线程间的同步,当多个线程都需要访问共享代码区域时,对共享代码区域进行加锁,使得每一次只能有一个线程访问共享代码区域,从而保证线程间的安全性. 因为没有显式的加锁和解锁过程,所以称之为隐式锁,也叫作内置锁.监视器锁. 如下实例,在没有使用synchronize

  • 详解Java并发编程之volatile关键字

    目录 1.volatile是什么? 2.并发编程的三大特性 3.什么是指令重排序? 4.volatile有什么作用? 5.volatile可以保证原子性? 6.volatile 和 synchronized对比 总结 1.volatile是什么? 首先简单说一下,volatile是什么?volatile是Java中的一个关键字,也是一种同步机制.volatile为了保证变量的可见性,通过volatile修饰的变量具有共享性.修改了volatile修饰的变量,其它线程是可以读取到最新的值的 2.并

随机推荐