并发 vs 并行

首先,我们先来搞清楚概念以及并发和并行的区别。

并发 - 利用时间片切换来实现“同时”运行的。

并行 - 利用CPU的多核来实现通过多线程来实现同时运行。

Go 语言的设计理念就是通过高并发的方式来进行效率的提升。

goroutine

在go语言中,我们就是通过goroutine的方式来处理高并发任务的。

goroutine 实际上是官方版本的“超级线程池”,每个实例只有4-5KB的栈内存大小,而且它的创建和销毁非常的快速。我们在使用 goroutine 的时候,还可以指定CPU的核数来进一步发挥其高并发处理的优势。

上面说了很多理论,是时候来写一写code啦。。。第一个goroutine示例

// concurrency.go
package main import (
"fmt"
) func play() {
fmt.Println("let's go!")
} func main() {
go play() // 使用 "go" 关键字来表示以goroutine的方式调用play方法
}

output:

从输出中,我们并没有看到所期望的字符串被打印出来,是什么原因呢?? 原来,goroutine的调用即开启了多线程,play方法是在另一个线程中被调用,并且主线程在此刻并没有被阻塞,因此我们的程序直接执行完毕(并没有打印出东东。。。)

那要如何才能看到输出呢,最简单的办法就是让主线程阻塞一小会,强制等待其他线程先结束。 于是我们可以这样:

// concurrency.go
package main import (
"fmt"
"time" //import 'time' package
) func play() {
fmt.Println("let's go!")
} func main() {
go play()
time.Sleep( * time.Second) // force to suspend main thread
}

output:

我们虽然实现了功能,但是code不够优雅,那么怎样才能流畅的在主/从线程之间切换呢??

Channel

channel 是为goroutine通信所服务的。用来实现同步或者异步调用。

使用make关键字来创建channel,完成后使用close关闭channel.

channel 是引用类型,因此可以直接修改它的字段或状态。

我们来改写前一个示例:

// concurrency.go
package main import (
"fmt"
) func main() {
channel := make(chan bool) // define channel
go func() { // define anonymous function
fmt.Println("let's go go go...")
channel <- true //resume
}()
<-channel // suspend
  close(channel)
}

output:

我们来分析一下程序的执行

1. 首先在主线程(main)里面定义channel,匿名函数。

2. 使用goruntine的方式调用函数(子线程开始执行,调用方法);主线程继续执行。

3. 这时候,主线程发现channel读取其中的信号量(没有被设置),此时主线程阻塞。

4. 子线程调用方法完成,在函数最后更新信号量。

5. 主线程轮询信号量(已经赋值完成),主线程恢复。

使用for... range迭代channel(取值)

我们可以用手动迭代的方式来等待信号量,例如

func main() {
channel := make(chan bool)
go func() { // define anonymous function
fmt.Println("let's go go go...")
channel <- false
close(channel)
}()
for v := range channel {
fmt.Println(v)
}
//<-channel
//close(channel)
}

channel 同步与异步

在使用 channel的时候,我们可以为其设置缓存,通过设置缓存,可以达到同步或者异步的效果。简单来说,当我们不指定缓存的时候,默认值为0,所以在读取的时,如果没读到,就会一直轮询等待。反之,若我们设置了缓存 (>0),再读取的时候会根据缓存忽略轮询,线程则不会阻塞(异步)。

func main() {
channel := make(chan bool, )
go func() { // define anonymous function
fmt.Println("let's go go go...")
<-channel
}() channel <- false
close(channel)
}

运行上面的code,我们发现不会输出内容。。。原因就是设置了缓存(2),当缓存没有被填满的时候,主线程不再阻塞。

Select

当我们需要使用多个channel的时候,就可以通过select来实现。

func main() {
c1, c2 := make(chan int), make(chan string)
c3 := make(chan bool)
go func() { // define anonymous function
for {
select {
case v, ok := <-c1:
if !ok {
c3 <- true
break
}
fmt.Println("c1", v)
case v, ok := <-c2:
if !ok {
c3 <- true
break
}
fmt.Println("c2", v)
}
} }() c1 <-
c2 <- "hi"
close(c1)
close(c2) <-c3
}
--output:
c1
c2 hi

我们还可以使用空select来阻塞主线程

func main() {
fmt.Print("the main thread will be suspended...")
select {}
}

注:这段code只是说明了一下情况,实际当中并不能这样写呀。。。

Go - concurrency的更多相关文章

  1. Concurrency

    <Concurrency>:http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html <Java ...

  2. Concurrency != Parallelism

    前段时间在公司给大家分享GO语言的一些特性,然后讲到了并发概念,大家表示很迷茫,然后分享过程中我拿来了Rob Pike大神的Slides <Concurrency is not Parallel ...

  3. actor concurrency

    The hardware we rely on is changing rapidly as ever-faster chips are replaced by ever-increasing num ...

  4. Optimistic Concurrency VS. Pessimistic Concurrency Control

    原创地址:http://www.cnblogs.com/jfzhu/p/4009918.html 转载请注明出处   (一)为什么需要并发控制机制 并发控制机制是为了防止多个用户同时更改同一条数据,也 ...

  5. Concurrency vs. Parallelism

    http://getakka.net/docs/concepts/terminology Terminology and Concepts In this chapter we attempt to ...

  6. Spike Notes on Lock based Concurrency Concepts

    Motivation 承并发编程笔记Outline,这篇文章专注于记录学习基于锁的并发概念的过程中出现的一些知识点,为并发高层抽象做必要的准备. 尽管存在Doug Lee开山之作Concurrent ...

  7. 使用Concurrency Visualizer优化性能

    Concurrency Visualizer: https://msdn.microsoft.com/en-us/library/dd537632.aspx?f=255&MSPPError=- ...

  8. 数据访问模式:数据并发控制(Data Concurrency Control)

    1.数据并发控制(Data Concurrency Control)简介 数据并发控制(Data Concurrency Control)是用来处理在同一时刻对被持久化的业务对象进行多次修改的系统.当 ...

  9. 第17/24周 悲观并发控制(Pessimistic Concurrency)

    大家好,欢迎回到性能调优培训.今天标志着第5个月培训的开始,这个月我们会谈论SQL Server里的锁.阻塞和死锁(Locking, Blocking, and Deadlocking). SQL S ...

  10. 第18/24周 乐观并发控制(Optimistic Concurrency)

    大家好,欢迎回到性能调优培训.上个星期我通过讨论悲观并发模式拉开了第5个月培训的序幕.今天我们继续,讨论下乐观并发模式(Optimistic Concurrency). 行版本(Row Version ...

随机推荐

  1. [ERR] Node 172.168.63.202:7001 is not empty. Either the nodealready knows other nodes (check with CLUSTER NODES) or contains some

    关于启动redis集群时: [ERR] Node 172.168.63.202:7001 is not empty. Either the nodealready knows other nodes ...

  2. photo

    我们在android开发过程中 经常有做到发图片或修改上传头像的功能 即要调用系统相册 如何调用系统相册并处理返回的数据呢?因为随着android手机系统的提高 不同系统的手机对调用相册并处理相册不同 ...

  3. Servlet的优化.GenericServlet

    如何更好的使用servlet?GernericServlet可以由自己仿照一个出来,下面就是介绍了如何写这样的一个类 1.init方法 妥善的保存config对象 2.空参init方法,为了防止开发人 ...

  4. 使用DBCP连接池对连接进行管理

    //需要引用的jar包有4个,分别是commons-pool2-2.4.2.jar.commons-dbcp2-2.1.1.jar.mysql-connector-java-5.1.42-bin.ja ...

  5. 【JAVAWEB学习笔记】27_Redis:在Linux上的安装、Jedis和常用命令

    一.Redis简介 1.关于关系型数据库和nosql数据库 关系型数据库是基于关系表的数据库,最终会将数据持久化到磁盘上,而nosql数据     库是基于特殊的结构,并将数据存储到内存的数据库.从性 ...

  6. ES6核心内容精讲--快速实践ES6(一)

    前言 本文大量参考了阮一峰老师的开源教程ECMAScript6入门,适合新手入门或者对ES6常用知识点进行全面回顾,目标是以较少的篇幅涵盖ES6及部分ES7在实践中的绝大多数使用场景.更全面.更深入的 ...

  7. 2.Java 加解密技术系列之 MD5

    Java 加解密技术系列之 MD5 序 背景 正文 结束语 序 上一篇文章中,介绍了最基础的编码方式 — — BASE64,也简单的提了一下编码的原理.这篇文章继续加解密的系列,当然也是介绍比较基础的 ...

  8. 元类(meta class)

    元类(meta class),这个名字想必很多人都听过,网上也有很多关于元类的介绍,今天我就按照自己这两天的理解来简单探讨一下这个玩意,有误之处还望指出. 首先,下载objc源码,源码地址:https ...

  9. c语言项目开发流程二部曲

    一.在第一部曲中我们介绍了电子词典项目开发的前5步,下面继续我们的步伐. 6.函数接口设计,这一步不是一蹴而就的,在项目进行中得不断修改,下面是我电子词典项目接口. /**************函数 ...

  10. ElasticSearch的Marvel更新license

    Marvel安装的时候需要申请一个license,否则只有30天的使用时间,到期后最多保存7天的监控数据,为了造成不必要的监控数据丢失,建议安装的同时注册一个lincense,方法如下: 1.     ...