Go语言Goroutinue和管道效率详解
作者:山与路 发布时间:2024-02-02 18:19:09
goroutinue基本介绍
进程和线程说明
进程介绍程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位
线程只是进程的一个执行实例或流程,是程序执行的最小单元
一个进程可以有多个线程,但是一个线程只能对应一个进程
同一个进程中的多个线程可以并发执行
程序:运行起来的应用程序就称为进程,也就是当程序不运行的时候我们称为程序,当程序运行起来他就是一个进程,通俗的理解就是不运行的时候是程序,运行起来就是进程。程序只有一个,但是进程有多个
并发和并行
并发:多个任务依次执行,执行过程中多个任务可以替换执行,在某一个时刻是一个任务在执行,但是在某个时间段内是多个任务在执行。
并行:多个任务没有顺序,同时执行,最终的执行结果跟耗时最长的任务有关
串行:多个任务依次执行,上一个任务没有完成时不能执行后续的任务,最明显的同步执行过程
同步和异步
同步:描述的就是串行执行过程,多个任务按照顺序依次执行的过程
异步:描述的就是并发和并行的过程,就是多个任务在一个时间段内同时执行,每个任务都不会等待其他任务执行完成后执行
Go协程和Go主线程
Go主线程:一个Go线程上,可以起多个协程,协程是轻量级的线程
go协程特点
有独立的栈空间
共享程序堆空间
调度由用户控制
协程是轻量级的线程
goroutinue基本使用
实验代码
package main
import (
"fmt"
"runtime"
"strconv"
"time"
)
func main() {
//编写一个函数,每隔1s输出"hello,world"
//要求主线程和gorutine同时执行
go test()
//在主线程中,开启一个goroutine,该协程每隔1s输出"hello,world"
for i:=1;i<=10 ; i++ {
fmt.Println("main() hello world", strconv.Itoa(i))
time.Sleep(time.Second)
}
//查询Golang运行的cpu数
fmt.Println(runtime.NumCPU()) //4
//设置Golang运行的cpu数
//runtime.GOMAXPROCS(runtime.NumCPU()-1)//3
}
func test(){
for i:=1;i<=10 ; i++ {
fmt.Println("test() hello world",strconv.Itoa(i))
time.Sleep(time.Second)
}
}
效果图
执行流程图
goroutinue的调度模型
MPG
MPG运行状态1
MPG运行状态2
管道(channel)
不同协程之间如何通讯
全局变量加锁同步
channel
使用全局变量加锁同步改进程序
因为没有对全局变量加锁,因此会出现资源夺取问题,代码会出现错误,提示concurrent map writes
加入互斥锁
全局变量加锁同步缺陷
主线程在等待所有goroutine全部完成的时间很难确定
如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有goroutine处于工作状态,这时也会随着主线程的结束而结束
不利于多个协程对全局变量的读写操作
管道基本介绍
管道本质介绍一个数据结构-队列
数据是先进先出
线程安全,无需加锁
管道有类型
管道基本使用 声明和定义
管道关闭和遍历
关闭
使用内置函数close可以关闭channel,关闭后,就不能写入数据,但可读
遍历
在使用for--range遍历时,如果channel没有关闭,则回出现deadlock错误
在使用for--range遍历时,如果channel已经关闭,则会正常遍历数据
代码
package main
import "fmt"
func main() {
//定义管道
var intChan chan int
intChan =make(chan int,3)
//写入数据
intChan<-10
intChan<-20
intChan<-30
//遍历
close(intChan) //关闭管道
for value := range intChan {
fmt.Printf("%d\t",value) //102030
}
}
管道注意事项
-`channel可以声明为只读,或者只写性质
使用select可以解决从管道取数据的阻塞问题
goroutine中使用recover,解决协程中出现panic,导致程序崩溃问题
综合案例
package main
import "fmt"
func main() {
numChan := make(chan int, 2000)
resChan := make(chan int, 2000)
exitChan := make(chan bool, 8)
go putNum(numChan) //存放数据
//开启八个协程
for i := 0; i < 8; i++ {
go add(numChan, resChan, exitChan)
}
go func() {
for i:=0;i<8 ;i++ {
<-exitChan
}
close(resChan)
}()
for i := 1; i <=2000 ; i++ {
fmt.Printf("resChan[%d]=%d\n", i, <-resChan)
}
}
func putNum(numChan chan int) {
for i := 1; i <= 2000; i++ {
numChan <- i
}
close(numChan)
}
func add(numChan chan int, resChan chan int, exitChan chan bool) {
for {
n,ok := <-numChan
if !ok{
break
}
res := 0
for i := 1; i <= n; i++ {
res += i
}
resChan <- res
}
exitChan<-true
}
来源:https://juejin.cn/post/7146113493295431716
猜你喜欢
- 本文实例讲述了Python迭代器定义与简单用法。分享给大家供大家参考,具体如下:一、什么是迭代器迭代,顾名思义就是重复做一些事很多次(就现在
- 简介:Mysql数据库按时间点恢复实战对于任何一家企业来讲,数据都是最宝贵的财富。如何保护数据完整性,数据不受损坏,在发生故障时,如何保住数
- 如下所示:a, b, c = 1, 2, 3 # 1.常规 if a>b: &nbs
- 1、数据库--所有数据库的大小 exec sp_helpdb --所有数据库的状态 sel
- 在MySQL中,一个字符串中,如果某个序列具有特殊的含义,则这个序列以反斜线符号(‘\’)开头,称为转义字符。常见的转义字符:\0 ASCI
- asp数字分页涵数参数说明:SQL: 查询语句,PageSizeN: 每页显示多少新闻记录classid: 栏目ID,PageCountS:
- 建立池连接可以显著提高应用程序的性能和可缩放性。SQL Server .NET Framework 数据提供程序自动为 ADO.NET 客户
- 格式良好的SQL并不会比乱七八糟的SQL运行效果更好。数据库其实不怎么关心SQL语句中你把逗号放到了字段名的前面还是后面。为了你自己思路清楚
- 解析接口返回数据1、把json格式的数据转换成单个{key,value}的形式,并把每个dict存入listdef parse(self,d
- 配置Laravel 的邮件服务可以通过 config/mail.php 配置文件进行配置。邮件中的每一项都在配置文件中有单独的配置项,甚至是
- 本文实例为大家分享了python使用Matplotlib画条形图的具体代码,供大家参考,具体内容如下数据中国的四个直辖市分别为北京市、上海市
- 用法:matplotlib.pyplot.stem(*args, linefmt=None, markerfmt=None, basefmt
- 本文代码需要正确安装Python扩展库pywin32,建议下载whl文件进行离线安装。然后调用win32api的ShellExecute()
- 内容摘要:现在博客很流行,相信应该上网时间稍微长点的朋友都会在这或者在那的有一个自己的博客。对于一些有一定能力的朋友,可能更喜欢自己去下载一
- 以下为引用的内容: <html> <head> <title>不刷新页面查询的方法&
- 在安装SQL Server 2005 时出现ASP.Net版本注册要求(警告),提示找不到ASP.Net 在 Microsoft Inter
- Java读取数据库表package com.easycrud.builder;import com.easycrud.utils.Prope
- Python入门 本系列为Python学习相关笔记整理所得,IT人
- 现在大部分网站都使用asp+access构建,这样的话通过下载access数据库简单就可以对网站进行破坏! 而很多的网站都不太重
- 下面是我们经常会用到且非常有用的MySQL命令。下面你看到#表示在Unix命令行下执行命令,看到mysql>表示当前已经登录MySQL