前言

Go语言通过routine,提供了并发编程的支持。

Routine特性

(1) goroutine是Go语言运行库的功能,不是操作系统提供的功能,goroutine不是用线程实现的。

例:启动一个routine

go + 函数名即可启动一个goroutine

package main
import (
"fmt"
)
func p() {
fmt.PrintLn("hello py")
}
func main() {
go p()
}

(2) goroutine就是一段代码,一个函数入口,以及在堆上为其分配的一个堆栈。所以它非常廉价,我们可以很轻松的创建上万个goroutine,但它们并不是被操作系统所调度执行。
(3) 除了被系统调用阻塞的线程外,Go运行库最多会启动$GOMAXPROCS个线程来运行goroutine。

例:使用GOMAXPROCS(设置CPU数)

package main

import (
"runtime"
"time"
) var _ = runtime.GOMAXPROCS(3) var a, b int func u1() {
a = 1
b = 2
} func u2() {
a = 3
b = 4
} func p() {
println(a)
println(b)
} func main() {
go u1()
go u2()
go p()
time.Sleep(1 * time.Second)
}

(4) goroutine是协作式调度的,如果goroutine会执行很长时间,而且不是通过等待读取或写入channel的数据来同步的话,就需要主动调用Gosched()来让出CPU。

例:Gosched()让出CPU

package main

import (
"fmt"
"runtime"
) func say(s string) {
for i := 0; i < 2; i++ {
runtime.Gosched()
fmt.Println(s)
}
} func main() {
go say("world")
say("hello")
}

(5) 和所有其他并发框架里的协程一样,goroutine里所谓“无锁”的优点只在单线程下有效,如果$GOMAXPROCS > 1并且协程间需要通信,Go运行库会负责加锁保护数据,这也是为什么sieve.go这样的例子在多CPU多线程时反而更慢的原因。
(6)
Web等服务端程序要处理的请求从本质上来讲是并行处理的问题,每个请求基本独立,互不依赖,几乎没有数据交互,这不是一个并发编程的模型,而并发编程框架只是解决了其语义表述的复杂性,并不是从根本上提高处理的效率,也许是并发连接和并发编程的英文都是concurrent吧,很容易产生“并发编程框架和coroutine可以高效处理大量并发连接”的误解。
(7) Go语言运行库封装了异步IO,所以可以写出貌似并发数很多的服务端,可即使我们通过调整$GOMAXPROCS来充分利用多核CPU并行处理,其效率也不如我们利用IO事件驱动设计的、按照事务类型划分好合适比例的线程池。在响应时间上,协作式调度是硬伤。
(8) goroutine最大的价值是其实现了并发协程和实际并行执行的线程的映射以及动态扩展,随着其运行库的不断发展和完善,其性能一定会越来越好,尤其是在CPU核数越来越多的未来,终有一天我们会为了代码的简洁和可维护性而放弃那一点点性能的差别。

Routine通信:Channel

routine之间是通过Channel进行通信的;Channel是进程内的通信,不支持进程外的通信。

语法

// 声明方式,在此ElemType是指此管道所传递的类型
var chanName chan ElemType
// 声明一个传递类型为int的管道
var ch chan int
// 声明一个map,元素是bool型的channel
var m map[string] chan bool
// 定义语法,定义需要使用内置函数make()即可,下面这行代码是声明+定义一个整型管道
ch := make(chan int)
// 事先定义好管道的size,下面这行代码定义管道的size为100
ch := make(chan int, 100) // 由管道中读写数据,<-操作符是与最左边的chan优先结合的
// 向管道中写入一个数据,在此需要注意:向管道中写入数据通常会导致程序阻塞,直到有
// 其他goroutine从这个管道中读取数据
ch<- value
// 读取数据,注意:如果管道中没有数据,那么从管道中读取数据会导致程序阻塞,直到有数据
value := <-ch // 单向管道
var ch1 chan<- float64 // 只能向里面写入float64的数据,不能读取
var ch2 <-chan int // 只能读取int型数据 // 关闭channel,直接调用close()即可
close(ch)
// 判断ch是否关闭,判断ok的值,如果是false,则说明已经关闭(关闭的话读取是不会阻塞的)
x, ok := <-ch

什么样的场景使用管道?

首先我们知道Channel可以在routine中进行通信,如下例:

package main
import "fmt" func print() {
fmt.Println("Hello world")
} func main() {
for i := 0; i < 10; i++ {
go print()
}
}

上面的代码意思大致是:使用协程来并行输出10次 "Hello world", 但是大家运行上面代码的时候,会发现不会有输出。这是因为虽然使用go关键字进行了协程的创建,但是还没有等到执行的时候,main函数已经退出来了,进程已经关闭,所以起来的协程也不会被执行。

如果你有C相关的多线程经验时,可已经将协程改为线程,之后调用线程的join方法,让主线程等待子线程执行完毕后再退出。而在Go语言中,我们可以利用管道的写入阻塞和读取阻塞来完成类似线程join的行为。代码如下所示:

package main
import "fmt" func print(ch chan int) {
fmt.Println("Hello world")
ch<- 1
} func main() {
chs := make([]chan int)
for i := 0; i < 10; i++ {
chs[i] = make(chan int)
go print(chs[i])
} for _, ch := range(chs){
<-ch
}
}

通过以上代码,我们就可以完成了并行输出10行Hello world 的效果。

Go语言的核心Routine-Channel的更多相关文章

  1. Go语言中的管道(Channel)总结

    管道(Channel)是Go语言中比较重要的部分,经常在Go中的并发中使用.今天尝试对Go语言的管道来做以下总结.总结的形式采用问答式的方法,让答案更有目的性. Q1.管道是什么? 管道是Go语言在语 ...

  2. go语言之并发编程 channel

    前面介绍了goroutine的用法,如果有多个goroutine的话相互之间是如何传递数据和通信的呢.在C语言或者JAVA中,传输的方法包括共享内存,管道,信号.而在Go语言中,有了更方便的方法,就是 ...

  3. php语言的核心知识点

    PHP:脚本语言,网站建设,服务器端运行PHP定义:一种服务器端的 HTML 脚本/编程语言,是一种简单的.面向对象的.解释型的.健壮的.安全的.性能非常之高的.独立于架构的.可移植的.动态的脚本语言 ...

  4. go语言之进阶篇 channel介绍

    1.channel介绍 和map类似,channel也一个对应make创建的底层数据结构的引用. 当我们复制一个channel或用于函数参数传递时,我们只是拷贝了一个channel引用,因此调用者何被 ...

  5. go语言之并发编程 channel(1)

    单向channel: 单向通道可分为发送通道和接收通道.但是无论哪一种单向通道,都不应该出现在变量的声明中,假如初始化了这样一个变量 var uselessChan chan <- int =m ...

  6. 大神是如何学习 Go 语言之 Channel 实现原理精要

    转自: https://mp.weixin.qq.com/s/ElzD2dXWeldYkJmVVY6Djw 作者Draveness Go 语言中的管道 Channel 是一个非常有趣的数据结构,作为语 ...

  7. [程序设计语言]-[核心概念]-02:名字、作用域和约束(Bindings)

    本系列导航 本系列其他文章目录请戳这里. 1.名字.约束时间(Binding Time) 在本篇博文开始前先介绍两个约定:第一个是“对象”,除非在介绍面向对象语言时,本系列中出现的对象均是指任何可以有 ...

  8. [java学习笔记]java语言核心----面向对象基础

    1.面向对象概述 面向对象是java语言的核心.是对应于面向过程而言的. 面向过程:强调的是过程,即动作.在java中动作就是函数.C语言就是面向过程的. 如:把大象装进冰箱需要几步? 答:需要三步: ...

  9. 第一周-----Java 的核心优势和生态体系——程序员们希望他们编写的程序能够运行在不同的机器,不同的环境中,这需要一种体系中立的语言(即跨平台)。

    跨平台是Java 语言的核心优势,赶上最初互联网的发展,并随着互联网的发展而发展,建立了强大的生态体系,目前已覆盖IT各个行业的“第一大语言,称为IT界的英语”

随机推荐

  1. Ubuntu16.04 中 Vscode 如何断点调试C语言程序

    个人博客链接:Ubuntu16.04 中 Vscode 如何断点调试C语言程序 问题:环境是 Ubuntu16.04,如何使用 Vscode 断点调试C语言程序. 写代码没有调试环境是不能忍受的,所以 ...

  2. [SCOI2011] 糖果

    luogu Description 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到 ...

  3. 【Linux】 Linux权限管理与特殊权限

    Linux权限管理 权限管理这方面,非常清楚地记得刚开始实习那会儿是仔细研究过的,不知道为什么没有笔记留痕..除了一些基本的知识点早就忘光了,无奈只好从头开始学习一遍.. ■ 基本权限知识 这部分实在 ...

  4. Spring Boot 2.0(五):Docker Compose + Spring Boot + Nginx + Mysql 实践

    我知道大家这段时间看了我写关于 docker 相关的几篇文章,不疼不痒的,仍然没有感受 docker 的便利,是的,我也是这样认为的,I know your felling . 前期了解概念什么的确实 ...

  5. Lucene详解

    一.lucene原理 Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎.它不是一个完整的搜索应用程序 ...

  6. JWT 简介

    JWT是一种用于双方之间传递安全信息的简洁的.URL安全的表述性声明规范.JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息 ...

  7. Repository个人实践

    1.背景 最近,有空了,想着把之前一些乱七八糟的小项目给整理一下,尤其是涉及到Repository.UoW几处.为此,专门查阅了博客园中几个大神 关于Repository的实践,到最后都感觉依然莫衷一 ...

  8. RESTFUL风格 put 报错 HTTP Status 405 - JSPs only permit GET POST or HEAD

    出现下图这种情况时是controller所return的jsp视图找不到, 所以提示请求只允许GET.POST.HEAD. 解决方案 1.若返回视图,把表单中name为_method的input值改为 ...

  9. 关于ORM,以及Python中SQLAlchemy的scoped_session

    orm(object relational mapping):对象关系映射. python面向对象,而数据库是关系型. orm是将数据库关系映射为Python中的对象,不用直接写SQL. 缺点是性能略 ...

  10. python中Properties的一些小用法

    property最大的用处就是可以为一个属性制定getter,setter,delete和doc,他的函数原型为: def __init__(self, fget=None, fset=None, f ...