golang channel本质——共享内存

channel是golang中很重要的概念,配合goroutine是golang能够方便实现并发编程的关键。channel其实就是传统语言的阻塞消息队列,可以用来做不同goroutine之间的消息传递,由于goroutine是轻量级的线程能够在语言层面调度,所以channel在golang中也常被用来同步goroutine。

一般channel的声明形式为:var chanName chan ElementType 
ElementType指定这个channel所能传递的元素类型。

定义一个channel也很简单,直接使用内置的函数make()即可: 
ch := make(chan int,bufferSize) //bufferSize为缓冲区的大小,可以不传递该值代表不带缓冲区的channel

消息传递

带有缓冲区的channel一般用来做不同goroutine之间的消息传递。最经典的解释莫过于生产者-消费者了。生产者向channel中写数据,如果channel缓冲区已满,则生产者会被阻塞直到消费者消费缓冲区中的数据后才能被唤醒。 
消费者从channel中读取数据,如果缓冲区中没有任何数据则消费者会阻塞直到生产者将数据写入才能被唤醒。

假设我们有30个学生做作业,做完作业后由一个老师批改作业。用go怎么实现呢,我们首先定义一个带有缓冲区HomeWork chan(缓冲区的大小与学生数目相同,主要是为了防止学生提交作业时阻塞),学生做完作业向hwChan中发送数据,老师等待hwChan中有数据就取出学生作业然后批改。

channel是消息传递的机制,用于多线程环境下lock free synchronization.

它同时具备2个特性:

1. 消息传递

2. 同步

channel的实现,都在$GOROOT/src/pkg/runtime/chan.c里

它是通过共享内存实现的

struct Hchan {

}

ch := make(chan interface{}, 5)
具体的实现是chan.c里的 Hchan* runtime·makechan_c(ChanType *t, int64 hint)
此时,hint=5, t=interface{}

它完成的任务就是:
分配hint * sizeof(t) + sizeof(Hchan)的内存空间[也就是说,buffered chan的buffer越大,占用内存越大]

ch <- 5
就会调用 void runtime·chansend(ChanType *t, Hchan *chan, byte *ep, bool *pres)
      lock(chan)
      如果chan是buffer chan {
            比较当前已经放入buffer里的数据是否满了A
            如果没有满 {
                  把ep(要放入到chan里的数据)拷贝到chan的内存区域 (此区域是sender/recver共享的)
                  找到receiver goroutine, make it ready, and schedule it to recv
            } else {
                  已经满了
                  把当前goroutine状态设置为Gwaiting

                  yield
            }

      } else {
            // 这是blocked chan
            找到receiver goroutine (channel的隐喻就是一定存在多个goroutine)
            让该goroutine变成ready (之前是Gwaiting), 从而参与schedule,获得控制权
            具体执行什么,要看chanrecv的实现
      }

参考:http://www.voidcn.com/blog/kjfcpua/article/p-2921075.html

http://shanks.leanote.com/post/%E6%B7%B1%E5%BA%A6%E5%89%96%E6%9E%90channel

时间: 2024-10-12 15:42:34

golang channel本质——共享内存的相关文章

golang channel 使用总结

原文地址 不同于传统的多线程并发模型使用共享内存来实现线程间通信的方式,golang 的哲学是通过 channel 进行协程(goroutine)之间的通信来实现数据共享: Do not communicate by sharing memory; instead, share memory by communicating. 这种方式的优点是通过提供原子的通信原语,避免了竞态情形(race condition)下复杂的锁机制.channel 可以看成一个 FIFO 队列,对 FIFO 队列的读

一个包从共享内存到达服务器

一个包到从共享内存到GS流程 上次说到一个包从共享内存池取到一个包之后放入共享队列中 hr = m_spShareMemInter->pushA(sd); 看看GS这边是如何取包的 主线程创建了一个子线程 void GameServer::ProcessThread() { try { ProcessThreadTry(); } catch (...) { DWORD dwErrno = GetLastError(); MessageBox(NULL, L"GameServer::proc

操作系统 进程间的通信 之 信号 消息队列 共享内存 浅析

[几个易混淆的相关概念] 进程互斥:指在多道程序环境下,每次只允许一个进程对临界资源进行访问. 进程同步:指多个相关进程在执行次序上的协调. 临界资源:在一段时间内只允许一个进程访问的资源. 临界区:每个进程中访问临界资源的那段代码. [进程通信] 现在常用的进程间通信方式有信号.信号量.消息队列.共享内存.通信,是一个广义的意义,不仅仅指传递一些 message.进程通信就是指不同进程之间进程数据共享和数据交换. [信号和信号量] 信号和信号量是不同的,他们虽然都可用来实现同步和互斥,但信号是

Oracle Study之--IPCS管理共享内存

Oracle Study之--IPCS管理共享内存 Unix/linux下的共享内存.信号量.队列信息管理 在unix/linux下,经常有因为共享内存.信号量,队列等共享信息没有干净地清除而引起一些问题. 查看共享信息的内存的命令是:ipcs [-m|-s|-q]. 默认会列出共享内存.信号量,队列信息 -m列出共享内存 -s列出共享信号量 -q列出共享队列 清除命令是:ipcrm [-m|-s|-q] id. -m 删除共享内存 -s删除共享信号量 -q删除共享队列. 案例分析: [[ema

C扩展 从共享内存shm到memcache外部内存

引言 - ipc - shm 共享内存 本文会通过案例了解ipc 的共享内存机制使用, 后面会讲解C 如何使用外部内存服务memcached. 好先开始了解 linux 共享内存机制. 推荐先参看下面内容回顾一下 共享内存 linux api. linux进程间的通信(C): 共享内存    http://blog.chinaunix.net/uid-26000296-id-3421346.html 上面文章可以简单看一下概念.  下面这篇文章好些, 可以细看加深共享内存api使用熟练度. Li

如何理解“不要通过共享内存来通信,而应该通过通信来共享内存”?

不要通过共享内存来通信,而应该通过通信来共享内存 这是一句风靡golang社区的经典语,对于刚接触并发编程的人,该如何理解这句话? 如何理解"不要通过共享内存来通信,而应该通过通信来共享内存"? >> golang 这个答案描述的挺清楚的:http://www.goodpm.net/postreply/golang/1010000008937789/如何理解不要通过共享内存来通信而应该通过通信来共享内存.html

Linux IPC之共享内存

System V共享内存机制: shmget  shmat  shmdt  shmctl 原理及实现: system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去.这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信. 共享内存允许一个或多个进程通过

Golang channel 的基本使用方法

package main import ( "fmt" "learner/Add" "time" ) //a. 普通类型,普通变量保存的就是值,也叫值类型 //b. 获取普通变量的内存地址,用&,比如: var a int, 获取a的内存地址:&a //c. 指针类型,指针变量存的就是一个内存地址,这个地址指向值 //d. 获取指针类型所指向的值,使用:*,比如:var *p int, 使用*p获取p指向的值 //e. 将一个内存

[golang] channel通道

说明 channel是go当中的一个核心类型,可以看做是管道.并发核心单元可以通过channel进行数据的发送和接收,从而实现通信. 在go中,channel是一种数据类型,主要被用来解决协程的同步问题以及协程之间数据共享(数据传递)的问题. go当中的goroutine运行在相同的地址空间,因此访问共享内存地址必须做好同步,goroutine奉行通过通信来共享内存,而不是共享内存来通信. 引用类型channel可用于多个goroutine通讯,在其内部实现了同步,确保并发安全. 定义chann