协程

1.并发是什么?

并发是指<立即>处理多个任务的能力。

比如你的双手可以同时做两件事,比如吃饭这件事就是并发,吃饭这个过程中,可以同时吃几种菜,甚至喝汤,这个过程就是一个多任务并发的过程,但是并发在时间上是不能同时进行的

2.并发和并行的却别

并行是指<同时>处理多个任务。这听起来和并发差不多,但其实完全不同。

一边吃饭一边听音乐,听音乐和吃饭可以在时间上同时进行

3.并行不一定有并发效率高

并行不一定会加快运行速度,因为并行运行的组件之间可能需要相互通信。在我们浏览器的例子里,当文件下载完成后,应当对用户进行提醒,比如弹出一个窗口。于是,在负责下载的组件和负责渲染用户界面的组件之间,就产生了通信。在并发系统上,这种通信开销很小。但在多核的并行系统上,组件间的通信开销就很高了。所以,并行不一定会加快运行速度!

4.Go 协程是什么?

Go 协程是与其他函数或方法一起并发运行的函数或方法。Go 协程可以看作是轻量级线程。与线程相比,创建一个 Go 协程的成本很小。因此在 Go 应用中,常常会看到有数以千计的 Go 协程并发地运行。

5.go协程 和 线程的优势对比

相比线程而言,Go 协程的成本极低。堆栈大小只有若干 kb,并且可以根据应用的需求进行增减。而线程必须指定堆栈的大小,其堆栈是固定不变的。 Go 协程会复用(Multiplex)数量更少的 OS 线程。即使程序有数以千计的 Go 协程,也可能只有一个线程。如果该线程中的某一 Go 协程发生了阻塞(比如说等待用户输入),那么系统会再创建一个 OS 线程,并把其余 Go 协程都移动到这个新的 OS 线程。所有这一切都在运行时进行,作为程序员,我们没有直接面临这些复杂的细节,而是有一个简洁的 API 来处理并发。 Go 协程使用信道(Channel)来进行通信。信道用于防止多个协程访问共享内存时发生竞态条件(Race Condition)。信道可以看作是 Go 协程之间通信的管道。我们会在下一教程详细讨论信道。

6.如何启动一个协程

调用函数或者方法时,在前面加上关键字 go,可以让一个新的 Go 协程并发地运行

package main

import (
    "fmt"
)

func hello() {
    fmt.Println("Hello world goroutine")
}
func main() {
    go hello()
    fmt.Println("main function")
}

下面再看一个例子

package main

import "fmt"

func print(i int){
    fmt.Println(i)
}

func main() {

 for  i := 1 ;i < 40 ;i++{
    go print(i)

 }

}

image.png

我们研究一下这个现象

import "fmt"

func print(i int){
    fmt.Println(i)
}

func main() {

 for  i := 1 ;i < 40 ;i++{
     go print(i)
     fmt.Printf("第 %d 循环",i)
 }

}

image.png

我们根据这个结果能得出三个结论?

  • 1.go print() 是并发执行了 因为输入的结构是无序的
  • 2.for 循环执行完毕的时候 go print() 没有执行完成
  • 3.当for 循环执行完毕的时候,如果 还有 go print() 的函数没有执行,那么系统就会回收资源,因为go 的协程的作用域是for的子块,for执行完毕后,它占用的内存就会被释放,那么它的子块作用域也会被释放

go 协程的理论如下

  • 启动一个新的协程时,协程的调用会立即返回。与函数不同,程序控制不会去等待 Go 协程执行完毕。在调用 Go 协程之后,程序控制会立即返回到代码的下一行,忽略该协程的任何返回值。
  • 如果希望运行其他 Go 协程,Go 主协程必须继续运行着。如果 Go 主协程终止,则程序终止,于是其他 Go 协程也不会继续运行

注意 main 函数其实调用也是一个协程,它被称为 主协程

package main

import "fmt"

func print(i int){
    fmt.Println(i)
}

func main() {

    go print(100)

}

猜猜会输出什么?

image.png

什么都不会输出,因为 print(100)还没执行完毕,main函数已经结束了,所以它的子协程也不会执行了

那怎么解决这个问题呢?

信道可用于在其他协程结束执行之前,阻塞 Go 主协程。请查看信道章节


go 协程的并发

package main

import (
    "fmt"
    "time"
)

func print(num int){
    for  i := 1 ;i < 10 ;i++ {
        fmt.Printf("%d -  第 %d 循环 \n",num, i)
    }
}

func main() {

  go print(1)
  go print(2)
  time.Sleep(1000 * time.Millisecond)
}

image.png

由于main 函数 会很快执行完毕 导致子协程 停止工作,所以我们加一个3秒的延时 让main 函数休眠,从而让它的两个个子协程能够执行执行完毕

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • net/http/pprof

    pprof包通过它的HTTP服务端提供pprof可视化工具期望格式的运行时剖面文件数据服务

    酷走天涯
  • 工作区介绍

    1.一个代码包可以有多个以.go为扩展名的源码文件组成如下,demo1.go demo2.go 和 main.go 都属于代码包main,注意同一个目录下的.g...

    酷走天涯
  • Swift3.0 - 检测API

    酷走天涯
  • 大数据时代需要转变的思维

    大数据时代要转变的思维: 要分析所有数据,而不是少量的数据样本 要追求数据的纷繁复杂,而不是精确性 要关注事物的相关关系,而不是因果关系 1. 分析所有数据,而...

    CSDN技术头条
  • 拍拍贷第四届魔镜杯大赛-冠亚季军方案梳理

    这是即2019腾讯广告算法之后,又一场数据竞赛。这次比赛以互联网金融信贷业务为背景,帮助选手了解相关业务。

    Coggle数据科学
  • 在ubuntun虚拟机里安装goLang语言编程环境

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。 https://jerry.bl...

    Jerry Wang
  • python_库学习_01

    可能会出现缺少依赖库的情况,依次安装,大概有lxml,pandas,bs4,requests,pandas依次安装后查看tushare官方文档详细接口的使用

    py3study
  • 大厂面试必备之设计模式:漫画单例模式

    饿汉模式中的类实例是当类被加载时就被初始化出来的,所以在应用初始化时,会占用不必要的内存。同时,由于该实例在类被加载的时候就创建出来了,所以他是线程安全的。因为...

    天才少年
  • Go-简洁的并发

    多核处理器越来越普及。有没有一种简单的办法,能够让我们写的软件释放多核的威力?是有的。随着Golang, Erlang, Scala等为并发设计的程序语言的兴起...

    李海彬
  • pytest文档58-随机执行测试用例(pytest-random-order)

    通常我们认为每个测试用例都是相互独立的,因此需要保证测试结果不依赖于测试顺序,以不同的顺序运行测试用例,可以得到相同的结果。 pytest默认运行用例的顺序是按...

    上海-悠悠

扫码关注云+社区

领取腾讯云代金券