码农桃花源
  • README
  • channel
    • 06 - 从一个关闭的 channel 仍然能读出数据吗
    • 12 - channel 有哪些应用
    • 08 - 如何优雅地关闭 channel
    • 10 - channel 在什么情况下会引起资源泄漏
    • 00 - 什么是 CSP
    • channel 底层的数据结构是什么
    • 09 - channel 发送和接收元素的本质是什么
    • 11 - 关于 channel 的 happened-before 有哪些
    • 04 - 向 channel 发送数据的过程是怎样的
    • 03 - 从 channel 接收数据的过程是怎样的
    • 07 - 操作 channel 的情况总结
    • 05 - 关闭一个 channel 的过程是怎样的
  • map
    • map 的底层实现原理是什么
    • 可以边遍历边删除吗
    • map 的删除过程是怎样的
    • 可以对 map 的元素取地址吗
    • 如何比较两个 map 相等
    • 如何实现两种 get 操作
    • map 是线程安全的吗
    • map 的遍历过程是怎样的
    • map 中的 key 为什么是无序的
    • float 类型可以作为 map 的 key 吗
    • map 的赋值过程是怎样的
    • map 的扩容过程是怎样的
  • interface
    • iface 和 eface 的区别是什么
    • Go 接口与 C++ 接口有何异同
    • 如何用 interface 实现多态
    • 接口转换的原理
    • Go 语言与鸭子类型的关系
    • 值接收者和指针接收者的区别
    • 接口的构造过程是怎样的
    • 编译器自动检测类型是否实现接口
    • 类型转换和断言的区别
    • 接口的动态类型和动态值
  • 标准库
    • context
      • context.Value 的查找过程是怎样的
      • context 如何被取消
      • context 有什么作用
      • context 是什么
    • unsafe
      • 如何利用unsafe包修改私有成员
      • Go指针和unsafe.Pointer有什么区别
      • 如何实现字符串和byte切片的零拷贝转换
      • 如何利用unsafe获取slice&map的长度
  • goroutine 调度器
    • M 如何找工作
    • goroutine 调度时机有哪些
    • 什么是 go shceduler
    • goroutine 如何退出
    • 描述 scheduler 的初始化过程
    • 什么是workstealing
    • mian gorutine 如何创建
    • 什么是M:N模型
    • g0 栈何用户栈如何切换
    • schedule 循环如何运转
    • GPM 是什么
    • schedule 循环如何启动
    • sysmon 后台监控线程做了什么
    • goroutine和线程的区别
    • 一个调度相关的陷阱
  • 编译和链接
    • 逃逸分析是怎么进行的
    • GoRoot 和 GoPath 有什么用
    • Go 编译链接过程概述
    • Go 编译相关的命令详解
    • Go 程序启动过程是怎样的
  • 反射
    • Go 语言中反射有哪些应用
    • 什么情况下需要使用反射
    • 如何比较两个对象完全相同
    • Go 语言如何实现反射
    • 什么是反射
  • 数组和切片
    • 数组和切片有什么异同
    • 切片作为函数参数
    • 切片的容量是怎样增长的
  • GC
    • GC
Powered by GitBook
On this page

Was this helpful?

  1. channel

00 - 什么是 CSP

Do not communicate by sharing memory; instead, share memory by communicating.

不要通过共享内存来通信,而要通过通信来实现内存共享。

这就是 Go 的并发哲学,它依赖 CSP 模型,基于 channel 实现。

CSP 经常被认为是 Go 在并发编程上成功的关键因素。CSP 全称是 “Communicating Sequential Processes”,这也是 Tony Hoare 在 1978 年发表在 ACM 的一篇论文。论文里指出一门编程语言应该重视 input 和 output 的原语,尤其是并发编程的代码。

在那篇文章发表的时代,人们正在研究模块化编程的思想,该不该用 goto 语句在当时是最激烈的议题。彼时,面向对象编程的思想正在崛起,几乎没什么人关心并发编程。

在文章中,CSP 也是一门自定义的编程语言,作者定义了输入输出语句,用于 processes 间的通信(communicatiton)。processes 被认为是需要输入驱动,并且产生输出,供其他 processes 消费,processes 可以是进程、线程、甚至是代码块。输入命令是:!,用来向 processes 写入;输出是:?,用来从 processes 读出。这篇文章要讲的 channel 正是借鉴了这一设计。

Hoare 还提出了一个 -> 命令,如果 -> 左边的语句返回 false,那它右边的语句就不会执行。

通过这些输入输出命令,Hoare 证明了如果一门编程语言中把 processes 间的通信看得第一等重要,那么并发编程的问题就会变得简单。

Go 是第一个将 CSP 的这些思想引入,并且发扬光大的语言。仅管内存同步访问控制(原文是 memory access synchronization)在某些情况下大有用处,Go 里也有相应的 sync 包支持,但是这在大型程序很容易出错。

Go 一开始就把 CSP 的思想融入到语言的核心里,所以并发编程成为 Go 的一个独特的优势,而且很容易理解。

大多数的编程语言的并发编程模型是基于线程和内存同步访问控制,Go 的并发编程的模型则用 goroutine 和 channel 来替代。Goroutine 和线程类似,channel 和 mutex (用于内存同步访问控制)类似。

Goroutine 解放了程序员,让我们更能贴近业务去思考问题。而不用考虑各种像线程库、线程开销、线程调度等等这些繁琐的底层问题,goroutine 天生替你解决好了。

Channel 则天生就可以和其他 channel 组合。我们可以把收集各种子系统结果的 channel 输入到同一个 channel。Channel 还可以和 select, cancel, timeout 结合起来。而 mutex 就没有这些功能。

Go 的并发原则非常优秀,目标就是简单:尽量使用 channel;把 goroutine 当作免费的资源,随便用。

Previous10 - channel 在什么情况下会引起资源泄漏Nextchannel 底层的数据结构是什么

Last updated 5 years ago

Was this helpful?