什么是协程?

  1. 协程类似于线程,但是比线程更加轻量。一个程序启动会占用一个进程 而一个进程可以拥有多个线程 ,一个线程可以拥有多个协程。
  2. 一个进程至少包含一个主线程,一个主线程可以有更多的子线程。 线程有两种调度策略,一是:分时调度,二是:抢占式调度。
  3. 对于操作系统来说 线程是最小的执行单元 进程是最小的资源管理单位 线程一般有五种状态:初始化、可运行、运行中、阻塞 、销毁。
  4. 协程是用户态执行,不由操作系统内核管理 是完全由程序自己调度和控制的 。
  5. 协程的创建、切换、挂起、销毁全部为内存操作。
  6. 协程属于线程,协程是在线程里面执行的。协程调度策略:协作式调度。

那世界上最好的语言:PHP中的swoole是如何执行协程的?

  • swoole 的协程客户端必须在协程上下文环境中使用
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go; run(function() {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$result = $redis->keys('*');
var_dump($result);
});

swoole协程是基于CSP 编程模型开发的。是单进程版协程,无法利用多核CPU。同一时间只有一个协程在调度。

go的goroutine

go是一个种对并发非常友好的语言。它提供了两大机制的简单语法:协程(goroutine)和管道(channel)

  • goroutine是轻量级的线程 go在语言层面就支持原生协程
  • go的协程相对于线程开销更小 大概在2kb 根据程序开销需求增大或者缩小 线程必须指定堆栈的大小 大小是固定的
  • goroutine 是通过 GPM 调度模型实现的。GPM 调度模型
  • 简单使用协程原生支持
package main

import (
"fmt"
"time"
) func main() {
fmt.Println("测试")
go func() {
fmt.Println("测试3")
}()
time.Sleep(time.Microsecond*10)
fmt.Println("测试3")
}
  • Go属于多线程版协程,可以利用多核CPU,同一时间可以有多个协程在调度,会存在并发问题。

下面这段代码,执行结果如何。按正常应该是打印1-20

package main

import (
"fmt"
"time"
)
var count =0 func main() {
for i:=0;i<=20;i++ {
go func() {
count ++
fmt.Println(count)
}()
}
time.Sleep(time.Microsecond*100)
}
$ go run main.go //第一次执行
1
3
5
2
14
18
19
10
11
12
13
6
15
16
17
4
8
20
9
7
21
$ go run main.go //第二次执行
1
3
18
2
5
7
8
19
10
11
12
13
14
15
16
17
4
9
20
21
6
  • 每次执行结果是不一样的
    在做写入操作的时候 同时多个协程写入 导致数据乱七八糟的打印
    从变量中读取变量是唯一安全的并发处理变量的方式。 你可以有想要多少就多少的读取者, 但是写操作必须要得同步。 有太多的方法可以做到这个了,包括使用一些依赖于特殊的 CPU 指令集的真原子操作。然而,常用的操作还是使用互斥量

  • 写入数据时给协程加锁

package main

import (
"fmt"
"sync"
"time"
) var (
lock sync.Mutex
count =0
) func main() {
for i:=0;i<=20;i++ {
go func() {
lock.Lock()
defer lock.Unlock()
count ++
fmt.Println(count)
}()
} time.Sleep(time.Microsecond*100)
}

我们在给count变量自增时加锁,保证同一时间只有一个协程在写入 结果和我们希望的结果一至。

$ go run main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

看似我们解决了并发问题,但也违背并发编程的初心。而且容易造成死锁问题。使用单个锁时,这没有问题,但是如果你在代码中使用两个或者更多的锁,很容易出现一种危险的情况,当协程 A 拥有锁 lockA ,想去访问锁 lockB ,同时协程 B 拥有锁 lockB 并需要访问锁 lockA 。

通道

通道是多协程调度资源共享的一个强大机制 是协程之间传递数据的共享管道。一个协程可以通过管道向另外一个协程传递数据 所以在任意一个时间点 只有一个协程可以访问数据

创建一个管道

c := make(chan int)
  • 这个通道的类型是 chan int。因此,要将通道传递给函数,我们的函数签名看起来是这个样子的:
func worker(c chan int) { ... }
  • 管道支持两个操作
//接收数据
CHANNEL <- DATA
//发送数据
VAR := <-CHANNEL
  • 使用 for 进行管道数据接收或者发送

举个例子

package main

import (
"fmt"
"time"
"math/rand"
) func main() {
c := make(chan int)
for i := 0; i < 5; i++ {
worker := &Worker{id: i}
go worker.process(c)
} for {
c <- rand.Int()
time.Sleep(time.Millisecond * 50)
}
} type Worker struct {
id int
} func (w *Worker) process(c chan int) {
for {
data := <-c
fmt.Printf("worker %d got %d\n", w.id, data)
}
}

缓冲通道

无缓冲管道的发送和接收过程是阻塞的,还可以创建一个有缓冲(Buffer)的管道。
只在缓冲已满的情况,才会阻塞向缓冲管道(Bufferer Channel)发送数据。同样,只有在缓冲为空的时候,才会阻塞从缓冲管道接收数据。
通过向make函数再传递一个表示容量的参数(指定缓冲的大小),可以创建缓冲管道。
要让一个管道有缓冲,上面语法中的capacity应该大于0。无缓冲管道的容量默认为0.

ch := make (chan type, capacity)

select

即使有缓冲,在某些时候我们需要开始删除消息。我们不能为了让 worker 轻松而耗尽所有内存。为了实现这个,我们使用 Go 的 select:

for {
select {
case c <- rand.Int():
// 可选的代码在这里
default:
// 这里可以留空以静默删除数据
fmt.Println("dropped")
}
time.Sleep(time.Millisecond * 50)
}

超时

timeout := make(chan bool, 1)
go func() {
time.Sleep(1e9) // 指定超时时长
timeout <- true
}()
select {
case <-ch: // read something from ch
case <-timeout: // 指定时间内没有读到内容,则从timeout中读取内容,程序继续运行,解决永久等待的问题
}

Go协程简单学习的更多相关文章

  1. Lua 5.3 协程简单示例

    Lua 5.3 协程简单示例 来源 http://blog.csdn.net/vermilliontear/article/details/50547852 生产者->过滤器->消费者 模 ...

  2. 关于协程的学习 & 线程栈默认10M

    先看的这篇文章:http://blog.csdn.net/qq910894904/article/details/41699541 以nginx为代表的事件驱动的异步server正在横扫天下,那么事件 ...

  3. Python学习---线程/协程/进程学习 1220【all】

    Python学习---线程基础学习 Python学习---线程锁/信号量/条件变量同步1221 Python学习---同步条件event/队列queue1223 Python学习---进程 1225 ...

  4. 聊聊并发,进程通信方式,go协程简单应用场景

    开篇提问 知道并发,并行,线程,协程概念吗?或者知道大概含义吗? 有线程为什么还要有协程?区别是什么? 『进程』通信方式知道几种?有没有超过3种? golang『协程』通信方式推荐? 使用并发的目的是 ...

  5. python之进程,线程,协程简单理解

    进程:资源单位,由操作系统控制调度.正在执行的一个程序或者过程,进程之间不共享资源,进程间通讯手段:管道,队列,信号量等.多用于计算密集型场景,如金融计算 线程:是cpu的最小执行单位,由操作系统控制 ...

  6. python 协程的学习记录

    协程是个子程序,执行过程中,内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行 从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数.可是,在协程中,yield 通常 ...

  7. Python3 协程相关 - 学习笔记

    什么是协程 协程的优势 Python3中的协程 生成器 yield/send yield + send(利用生成器实现协程) 协程的四个状态 协程终止 @asyncio.coroutine和yield ...

  8. 协程gevent学习

    import gevent def f1(): print(11) gevent.sleep(2) print(33) def f2(): print(22) gevent.sleep(1) prin ...

  9. 分析Tornado的协程实现

    转自:http://www.binss.me/blog/analyse-the-implement-of-coroutine-in-tornado/ 什么是协程 以下是Wiki的定义: Corouti ...

  10. Unity中的协程(一)

    这篇文章很不错的问题,推荐阅读英文原版: Introduction to Coroutines Scripting with Coroutines   这篇文章转自:http://blog.csdn. ...

随机推荐

  1. langchain0.3教程:从0到1打造一个智能聊天机器人

    在上一篇文章<大模型开发之langchain0.3(一):入门篇> 中已经介绍了langchain开发框架的搭建,最后使用langchain实现了HelloWorld的代码案例,本篇文章将 ...

  2. 【长知识】BIOS

    设置最新UEFI BIOS 本章导读 BIOS是电脑启动和操作的基础,若电脑系统中没有BIOS,则所有硬件设备都不能正常使用.UEFI是目前最新的BIOS类型,以后会逐渐取代传统的BIOS.本章将认识 ...

  3. 【Linux】速查手册

    查看Linux系统信息 arch #显示机器的处理器架构(1) uname -m #显示机器的处理器架构(2) uname -r #显示正在使用的内核版本 dmidecode -q #显示硬件系统部件 ...

  4. object中的usemap是什么-HTML

    <object> 标签中的 usemap 属性用于将嵌入的对象(如图像)与一个 图像映射(image map) 关联起来.图像映射允许你在图像的特定区域定义可点击的链接,用户点击这些区域时 ...

  5. 使用Python计算万有引力势能

    引言 在物理学中,万有引力是描述物体之间相互吸引的基本力之一.牛顿的万有引力定律告诉我们,任何两个物体之间都存在引力,这个引力与它们的质量和它们之间的距离有关.在这个定律中,万有引力势能是一个非常重要 ...

  6. 🎀idea - properties文件unicode中文显示

    简介 idea中properties文件中文默认展示为unicode码 unicode 中文展示为 \u开头的ASCII 调整中文显示 idea -> settings -> Editor ...

  7. MySQL插入异常:SQL state [HY000]; error code [1366]-----(utf8mb4)

    发现爬虫软件,爬取数据不及时,查询服务器日志发现异常: SQL state [HY000]; error code [1366] java.sql.SQLException: Incorrect st ...

  8. MCP应用docker部署,docker-compose部署

    一.概述 前面几篇文章,MCP应用直接用的python3 server.py运行的,如果服务器重启,进程就会关掉,很不方便. 所以需要使用docker部署,实现开机自启动. 二.docker部署 my ...

  9. 【FAQ】HarmonyOS SDK 闭源开放能力 —Health Service Kit

    1.问题描述: 按照官方文档调用healthStore API申请用户授权:有拉起授权弹窗,但是无回调,检查权限接口也无回调. 解决方案: 1.接口调用前,需先使用init方法进行初始化,没有回调的问 ...

  10. ThinkPHP3.2无法加载控制器

    无法加载控制器:Admin 错误位置 FILE: D:\phpStudy\WWW\wisdom\ThinkPHP\Library\Think\App.class.php LINE: 101 在将Thi ...