Go语言协程使用
主协程执行打印,子协程不打印
package main
import ("fmt"
)func do(i int) {fmt.Println("执行中")
}
func main() {fmt.Println("main协程")go do(1)fmt.Println("执行完了")
}//main协程
//执行完了
子协程没有打印输出
原因:主和子协程各执行各的,当主协程执行完go语句就退出,并不会等待子协程执行完成
解决办法三个:
sync. WaitGroup的三个方法 Add(), Done(), Wait()
package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)
}
func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer wg.Done()do(i)}(1)wg.Wait()fmt.Println("执行完了")
}//main协程
//do执行中 1
//执行完了
channel来控制协程
package mainimport ("fmt"
)func do(i int) {fmt.Println("do执行中", i)
}func main() {ch := make(chan bool, 1)fmt.Println("main协程")go func(i int, chp chan<- bool) {defer close(chp)A(i)fmt.Println("do执行完")chp <- true}(1, ch)fmt.Println("wait")<-chfmt.Println("main执行完了")
}//main协程
//wait
//do执行中 1
//do执行完
//main执行完了
通过sync. Cond来实现
package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)
}func main() {var locker = new(sync.Mutex)var cond = sync.NewCond(locker)var done bool = falsefmt.Println("main")cond.L.Lock()go func(i int) {do(i)fmt.Println("do完成")done = truecond.Signal()}(1)fmt.Println("wait")if !done {cond.Wait()cond.L.Unlock()}fmt.Println("main完成")
}//main
//do执行中
//do完成
//main完成
会出现的问题:协程崩溃,主协程也会停止
go可以通过recover来捕获panic,类似try catch的作用
注意
- recover如果想起作用的话, 必须在defered函数前声明,因为只要panic,后面的函数不会被执行
- recover函数只有在方法内部发生panic时,返回值才不会为nil,没有panic的情况下返回值为nil
package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)panic("崩溃")defer func() { //在panic后声明defer,不能捕获异常if err := recover(); err != nil {fmt.Println("恢复", err)}}()
}func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer wg.Done()A(i)}(1)wg.Wait()fmt.Println("main执行完了")
}main协程
do执行中 1
main执行完了
panic: 崩溃//goroutine 6 [running]:
//main.do(0x0?)
// /Volumes/disk/site/go/demo/gfqa/main.go:11 +0x88
//main.main.func1(0x0?)
// /Volumes/disk/site/go/demo/gfqa/main.go:28 +0x4c
//created by main.main
// /Volumes/disk/site/go/demo/gfqa/main.go:26 +0x100//进程 已完成,退出代码为 2
改进:panic前声明recover
package mainimport ("fmt""sync"
)func do(i int) {fmt.Println("do执行中", i)defer func() { //在panic后声明defer,不能捕获异常if err := recover(); err != nil {fmt.Println("恢复", err)}}()panic("崩溃")
}func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer wg.Done()A(i)}(1)wg.Wait()fmt.Println("main执行完了")
}//do执行中 1
//恢复 崩溃
//main执行完了
其他写法
func do(i int) {fmt.Println("do执行中", i)panic("崩溃")
}func main() {var wg sync.WaitGroupfmt.Println("main协程")wg.Add(1)go func(i int) {defer func() {if err := recover(); err != nil {fmt.Println("恢复", err)}wg.Done()}()do(i)}(1)wg.Wait()fmt.Println("main执行完了")
}
总结:如果在协程内执行其它函数时,为了保证不崩溃,安全的做法是,提前声明defer recover函数
协程超时控制
用select + channel来进行超时控制
超时 : ctx. Done()或者time. After()或者time. Ticket()
select捕获到其中一个channel有数据,就执行对应的代码,然后退出
注意:channel要用有缓冲的,不然,在超时分支退出时,协程还在卡住,造成goroutine泄露
func do(ctx context.Context, wg *sync.WaitGroup) {ctx, cancle := context.WithTimeout(ctx, time.Second*2)defer func() {cancle()wg.Done()}()done := make(chan struct{}, 1) //执行成功的channelgo func(ctx context.Context) {fmt.Println("go goroutine")time.Sleep(time.Second * 10)done <- struct{}{} //发送完成的信号}(ctx)select {case <-ctx.Done(): //超时fmt.Printf("timeout,err:%v\n", ctx.Err())case <-time.After(3 * time.Second): //超时fmt.Printf("after 1 sec.")case <-done: //程序正常结束fmt.Println("done")}}func main() {fmt.Println("main协程")ctx := context.Background()var wg sync.WaitGroupwg.Add(1)do(ctx, &wg)wg.Wait()fmt.Println("main执行完成")
}
//main协程
//go goroutine
//timeout,err:context deadline exceeded
//main执行完成
总结:runtime. GOMAXPROCS()可以控制当前程序运行时占用的系统核心数,
一个协程不对应一个os线程,是一个m:n的对应关系,协程对应的os线程runtime. GOMAXPROCS默认为系统逻辑cpu数量
相关文章:
Go语言协程使用
主协程执行打印,子协程不打印 package main import ("fmt" )func do(i int) {fmt.Println("执行中") } func main() {fmt.Println("main协程")go do(1)fmt.Println("执行完了") }//main协程 //执行完了子协程没有打印输出…...
JAVA如何创建对象
在 Java 中创建对象的步骤如下: 定义一个类:在 Java 中,所有的对象都是通过类来创建的。因此,首先需要定义一个类,即描述对象的属性和行为。 声明变量:要创建一个对象,需要先声明一个变量来保存…...

《WebKit 技术内幕》之五(2): HTML解释器和DOM 模型
2.HTML 解释器 2.1 解释过程 HTML 解释器的工作就是将网络或者本地磁盘获取的 HTML 网页和资源从字节流解释成 DOM 树结构。 这一过程中,WebKit 内部对网页内容在各个阶段的结构表示。 WebKit 中这一过程如下:首先是字节流,经过解码之…...
Spring Boot多环境配置
Spring Boot的针对不同的环境创建不同的配置文件, 语法结构:application-{profile}.properties profile:代表的就是一套环境 需求 application-dev.yml 开发环境 端口8090 application-test.yml 测试环境 端口8091 application-prod.yml 生产环境 端口80…...
常用的目标跟踪有哪些
目标跟踪是计算机视觉领域的一个重要研究方向,主要用于实现视频监控、人机交互、智能交通等领域。下面介绍几种常用的目标跟踪方法: 特征匹配法 特征匹配法是目标跟踪中最基本的方法之一,其基本原理是通过提取目标的特征,然后在…...

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-帖子详情页实现
锋哥原创的SpringbootLayui python222网站实战: python222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火…...

11、Kafka ------ Kafka 核心API 及 生产者API 讲解
目录 Kafka核心API 及 生产者API讲解★ Kafka的核心APIKafka包含如下5类核心API: ★ 生产者APIKafka 的API 文档 ★ 使用生产者API发送消息 Kafka核心API 及 生产者API讲解 官方文档 ★ Kafka的核心API Kafka包含如下5类核心API: Producer API&#x…...

MySQL 8.3 发布, 它带来哪些新变化?
1月16号 MySQL 官方发布 8.3 创新版 和 8.0.36 长期支持版本 (该版本 没有新增功能,更多是修复bug ),本文基于 官方文档 说一下 8.3 版本带来的变化。 一 增加的特性 1.1 GTID_NEXT 支持增加 TAG 选项。 之前的版本中 GTID_NEXTUUID:number ÿ…...

【数据结构】详谈队列的顺序存储及C语言实现
循环队列及其基本操作的C语言实现 前言一、队列的顺序存储1.1 队尾指针与队头指针1.2 基本操作实现的底层逻辑1.2.1 队列的创建与销毁1.2.2 队列的增加与删除1.2.3 队列的判空与判满1.2.4 逻辑的局限性 二、循环队列2.1 循环队列的实现逻辑一2.2 循环队列的实现逻辑二2.3 循环队…...

为什么 HTTPS 协议能保障数据传输的安全性?
HTTP 协议 在谈论 HTTPS 协议之前,先来回顾一下 HTTP 协议的概念。 HTTP 协议介绍 HTTP 协议是一种基于文本的传输协议,它位于 OSI 网络模型中的应用层。 HTTP 协议是通过客户端和服务器的请求应答来进行通讯,目前协议由之前的 RFC 2616 拆…...

使用 Node 创建 Web 服务器
Node.js 提供了 http 模块,http 模块主要用于搭建 HTTP 服务端和客户端,使用 HTTP 服务器或客户端功能必须调用 http 模块,代码如下: var http require(http); 以下是演示一个最基本的 HTTP 服务器架构(使用 8080 端口)&#x…...
leetcode 151反转字符串如何原地去除多余空格
题目:https://leetcode.cn/problems/reverse-words-in-a-string/description/ 完整题解:https://leetcode.cn/problems/reverse-words-in-a-string/solutions/2611893/chu-li-kong-ge-ku-han-shu-reversefan-zhu-bioo 思路来自代码随想录,对其中的除去多…...
面试问题记录【深圳,共三面,A 轮公司】
问题记录 一面: 自我介绍项目介绍项目中用到的本地缓存是否涉及数据不一致问题,如何解决?项目中用到了 RTree 和普通的 B 树和 B树的数据结构的区别是什么?mysql 数据库中几种日志的用法和区别?redis 中缓存三兄弟存…...
Mysql数据库cpu飙升怎么解决
排查过程 (1)使用top命令观察,确定是mysql导致还是其他原因。 (2)如果是mysql导致的,show processlist,查看session情况,确定是不是有消耗资源的sql在运行。 (3…...
PHP反序列化漏洞-POP链构造
POP链构造 POP链(Property-Oriented Programming)是一种常用于构造特定调用链的方法,用于从现有运行环境中寻找一系列代码或指令调用。它的目的是构成一组连续的调用链,最终达到攻击者恶意利用的目的。POP链实质上是通过控制对象的可控属性来控制程序的执行流程,从而利用…...

CentOS 7安装Java并配置环境
一、安装Java环境 1、检查系统是否安装Java [rootlocalhost ~]# java -version 2、更新系统软件包 [rootlocalhost ~]# yum update #遇到[y/n],选择y并回车,耐心等待下载完毕,之后系统会自动检验更新的软件包遇到 /var/run/yum.pid 已被锁定 /var/…...

Vagrant创建Oracle RAC环境示例
利用Vagrant安装Oracle RAC(默认为non-CDB模式),生成2台虚机,耗时约1小时。 node1: -----------------------------------------------------------------node1: INFO: 2024-01-11 18:25:54: Make create database commandnode1: …...

鸿蒙 HarmonyOS ArkTS ArkUI 动画 中心缩放、顶部缩放、纵向缩放
EntryComponentstruct Index {State widthA: number 200State heightA: number 200onPageShow():void{animateTo ( {duration: 2000,iterations: -1,curve:Curve.Linear}, () > {this.widthA 0this.heightA 0} )}build() {Column() {// 中心缩放Column(){}.width(this.wi…...

基于python socket实现TCP/UDP通信
两个应用程序如果需要进行通讯最基本的一个前提就是能够唯一的标示一个进程,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中…...
指针的运算
指针的运算 1.指针-整数 #define N_VALUES 5 float values[N_VALUES]; float* vp; //指针-整数:指针的关系运算 int main() { for (vp &values[0]; vp < &values[N_VALUES];) { *vp 0;//指针每自增一次,就是指向下一个元素的地址 } return …...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...