浅谈go 协程的使用陷阱

golang 语言协程

协程中使用全局变量、局部变量、指针、map、切片等作为参数时需要注意,此变量的值变化问题。 与for 循环,搭配使用更需谨慎。

1、内置函数时直接使用局部变量,未进行参数传递

func main() {
  for i := 0; i < 100; i++ {
    go func() {
      fmt.Println(i)
    }()
  }
}

运行效果

func main() {
  for i := 0; i < 100; i++ {
    go func(i int) {
      fmt.Println(i)
    }(i)
  }
}

运行效果

2、地址传递的参数

type Per struct {
  name string
  bh  int
}
func main() {
  p := &Per{}
  for i := 0; i < 100; i++ {
    p.bh = i
    go func(p *Per) {
      fmt.Println(p)
    }(p)
  }
}

分析: 导致以上非实际结果的原因是,go 之后并非立即启动协程的。

补充:Go for循环 协程间传递参数的一个问题

看代码吧~

map1 := make(map[int]int)
for i:=0; i<3; i++{
 map1[i] = i+1
}

fmt.Println(map1)
for k, v := range map1{
 go func(key, value int){
 fmt.Println("one way :", key, " : ", value)
 }(k, v)

 go func(){
 time.Sleep(time.Second)
 fmt.Println("another way :", k, " : ", v)
 }()
}

输出:

map[2:3 0:1 1:2]
one way : 1 : 2
one way : 0 : 1
one way : 2 : 3
another way : 2 : 3
another way : 2 : 3
another way : 2 : 3

这看起来跟 js 里面的 for 循环匿名函数传参的问题差不多。就是说匿名函数真正执行的时候,传入形参的值已经确定。

如果想要达到想要的效果需要进行第一种传参形式。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • Go语言Echo服务器的方法

    本文实例讲述了Go语言Echo服务器的方法.分享给大家供大家参考.具体如下: 复制代码 代码如下: package main import (     "net"     "io" ) func main() {     serv, e := net.Listen("tcp", ":12345")     if e != nil {         panic(e)     }     defer serv.Close()  

  • golang HTTP 服务器 处理 日志/Stream流的操作

    目前,我开发 HTTP 服务, 用的是 beego框架, 方便了很多. 但是, 有时候,还是会遇到一些 特殊的场景. 比如: 过滤日志. 这应该是一种典型的stream,同时数据量也适中, 不会有人,为了这个, 就用一些很重的框架. 可以这样直观的描述这个 逻辑 其他组件 产生 log || \ / 我的组件,业务处理 || \ / 用户, http client 这种情景下, 有几个特殊点: 1. 难以用 string,或者 byte 数组 收集数据 2. 数据Source 端,不断的有数据产

  • graphql---go http请求使用详解

    1. Graphql是什么? GraphQL是Facebook 在2012年开发的,2015年开源,2016年下半年Facebook宣布可以在生产环境使用,而其内部早就已经广泛应用了,用于替代 REST API.facebook的解决方案和简单:用一个"聪明"的节点来进行复杂的查询,将数据按照客户端的要求传回去,后端根据GraphQL机制提供一个具有强大功能的接口,用以满足前端数据的个性化需求,既保证了多样性,又控制了接口数量. GraphQL并不是一门程序语言或者框架,它是描述你的请

  • golang 获取当前执行程序路径的操作

    我就废话不多说了,大家还是直接看代码吧~ 1.获取当前执行程序路径 func execPath() (string, error) { file, err := exec.LookPath(os.Args[0]) if err != nil { return "", err } re, err := filepath.Abs(file) if err != nil { logs.Error("The eacePath failed: %s\n", err.Error

  • go获取协程(goroutine)号的实例

    我就废话不多说了,大家还是直接看代码吧~ func GetGID() uint64 { b := make([]byte, 64) b = b[:runtime.Stack(b, false)] b = bytes.TrimPrefix(b, []byte("goroutine ")) b = b[:bytes.IndexByte(b, ' ')] n, _ := strconv.ParseUint(string(b), 10, 64) return n } 补充:Go语言并发协程Go

  • go语言的工作空间和GOPATH环境变量介绍

    go语言并没有强制一定要使用一定的工作空间和项目结构,对于小型的go程序依靠go run等命令就可以直接编译运行. 然而,保持良好的工作空间和文件结构,对于管理源代码和发布程序都是非常有帮助的. 对于大型的go语言项目,工作空间则是一定要的. 1.go语言的工作空间结构 go语言的工作空间其实就是一个文件目录,目录中必须包含src.pkg.bin三个目录. 其中src目录用于存放go源代码,pkg目录用于package对象,bin目录用于存放可执行对象. 使用go的编译命令工具可以将源代码或pa

  • 解决go echo后端处理跨域的两种操作方式

    跨域问题一般需要在后台解决会比较好. 1.第一种方式当然是接受所有的跨域方式: func setAccessOriginUrl(c echo.Context) { c.Response().Header().Set("Access-Control-Allow-Origin", "*") } 2.第二种接受指定地址的跨域请求: func setAccessOriginUrl(c echo.Context) { c.Response().Header().Set(&qu

  • 浅谈go 协程的使用陷阱

    golang 语言协程 协程中使用全局变量.局部变量.指针.map.切片等作为参数时需要注意,此变量的值变化问题. 与for 循环,搭配使用更需谨慎. 1.内置函数时直接使用局部变量,未进行参数传递 func main() { for i := 0; i < 100; i++ { go func() { fmt.Println(i) }() } } 运行效果 func main() { for i := 0; i < 100; i++ { go func(i int) { fmt.Printl

  • 浅谈Python协程

    协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈.因此: 协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置. 协程的好处: 无需线程上下文切换的开销 无需原子操作锁定及同步的开销 "原子操作(atomic o

  • 浅谈Python协程asyncio

    一.协程 官方描述; 协程是子例程的更一般形式. 子例程可以在某一点进入并在另一点退出. 协程则可以在许多不同的点上进入.退出和恢复. 它们可通过 async def 语句来实现. 参见 PEP 492. 协程不是计算机内部提供的,不像进程.线程,由电脑本身提供,它是由程序员人为创造的, 实现函数异步执行. 协程(Coroutine),也可以被称为微线程,是一种用户太内的上下文切换技术,其实就是通过一个线程实现代码块相互切换执行.看上去像子程序,但执行过程中,在子程序内部可中断,然后转而执行别的

  • 浅谈Python 列表字典赋值的陷阱

    今天在用python刷leetcode 3Sum problem时,调入到了一个大坑中,检查半天并没有任何逻辑错误,但输出结果却总是不对,最终通过调试发现原来python中list和dict类型直接赋值竟然是浅拷贝!!!因此,在实际实验中,若要实现深拷贝,建立新list或dict,使新建的list或dict变量和以前的变量只是具有相同的值,但是却具有不同的存储地址,保证在改变以前的list变量的时候,不会对新的list产生任何影响. python中的深拷贝的实现需要通过copy.deepcopy

  • 详细解读tornado协程(coroutine)原理

    tornado中的协程是如何工作的 协程定义 Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations.. -- [ 维基百科 ] 我们在平常编程中,更习惯使用的是子

  • 浅谈golang for 循环中使用协程的问题

    两个例子 package main import ( "fmt" "time" ) func Process1(tasks []string) { for _, task := range tasks { // 启动协程并发处理任务 go func() { fmt.Printf("Worker start process task: %s\n", task) }() } } func main() { tasks := []string{&quo

  • 浅谈Java自动装箱与拆箱及其陷阱

    在本文中,笔者向大家介绍下Java中一个非常重要也非常有趣的特性,就是自动装箱与拆箱,并从源码中解读自动装箱与拆箱的原理,同时这种特性也留有一个陷阱.开发者如果不注意,就会很容易跌入这个陷阱. 自动装箱(Autoboxing) 定义 大家在平时编写Java程序时,都常常以以下方式来定义一个Integer对象: Integer i=100; 从上面的代码中,大家可以得知,i为一个Integer类型的引用,100为Java中的基础数据类型(primitive data type).而这种直接将一个基

  • react hooks闭包陷阱切入浅谈

    目录 引言 1.一个熟悉的闭包场景 2 浅谈hooks原理,理解useEffect 的 “闭包陷阱” 出现原因 2 难道真的要在依赖数组里写上的值,才能拿到新鲜的值? 3 为什么使用useRef能够每次拿到新鲜的值? 4 完毕 引言 首先,本文并不会讲解 hooks 的基本用法, 本文从 一个hooks中 “奇怪”(其实符合逻辑) 的 “闭包陷阱” 的场景切入,试图讲清楚其背后的因果.同时,在许多 react hooks 奇技淫巧的文章里,也能看到 useRef 的身影,那么为什么使用 useR

  • 浅谈对yield的初步理解

    如下所示: def go(): while True: data = 1 r = yield data # data是返回值,r是接收值 print("data", data) print("A1", r) data += 1 r = yield data print("data",data) r += r print("A2", r) data += 1 r = yield data print("data&quo

  • 浅谈Java线程池是如何运行的

    异步编程工具在Android开发中目前最被推荐的就是Kotlin协程,在引入Kotlin协程机制前,除了响应式扩展(RxJava)兼任异步编程工具外,Java API中线程与线程池就是最重要异步编程手段.而对于Android平台的Kotlin协程实现来说,依然使用的是线程池来作为任务执行的载体,所以可以将Android平台的Kotlin协程简单的理解是对线程池的一种高度封装. Executors.newFixedThreadPool(10).asCoroutineDispatcher() Dis

随机推荐