基于C++和Python基础的Golang学习笔记

文章目录

  • 一、基础
    • 1.DOS命令
    • 2.变量
      • (1)局部变量
      • (2)全局变量
      • (3)数据类型
      • (4)指针
      • (5)运算符
      • (6)自定义数据类型
    • 3.语句
      • (1)条件语句
      • (2)循环语句
    • 4.函数
      • (1)基础
      • (2)结构
  • 二、常用函数
    • 0.基础
      • (1)len() 和 cap()
      • (2)new()
      • (3)make(Type, len, cap)
      • (4)nil
      • (5)append() 和 copy()
      • (6)Range关键字
      • (7)_
      • (8)element()
      • (9).(type)
    • 1.package unsafe
      • (1)unsafe.Sizeof(num)
    • 2.import "fmt"
      • (1)输出
      • (2)输入
    • 3.import "strconv"
    • 4.字符串函数
    • 5.import "os"
    • 6.import "io"
    • 7.import "io/ioutil"
    • 8.import "bufio"
    • 9.import "sync"
  • 三、包及其函数
    • 1.包的引入
    • 2.init函数
    • 3.匿名函数与闭包
    • 4.defer关键字
    • 5.日期和时间函数
    • 6.错误处理
      • (1)错误捕获
      • (2)自定义错误
  • 四、数组、切片、映射
    • 1.数组
    • 2.切片 []
    • 3.集合/字典/映射 Map
  • 五、面向对象
    • 1.结构体
      • (1)基础
      • (2)转换
      • (3)方法的引入
      • (4)方法与函数的差别
      • (5)创建结构体实例
    • 2.封装
    • 3.继承
      • (1)基础
      • (2)注意事项
    • 4.接口
      • (1)基础
      • (2)注意事项
      • (3)多态
    • 6.断言
  • 六、文件操作
    • 1.文件
    • 2.io读取文件
    • 3.io写入文件
    • 4.文件复制操作
  • 七、协程和管道
    • 1.基本概念
      • (1)程序
      • (2)进程
      • (3)线程
      • (4)协程
    • 2.协程
      • (1)多协程
      • (2)延长协程存活
      • (3)互斥锁同步协程
      • (4)读写锁
    • 3.管道
      • (1)管道关闭
      • (2)管道遍历
      • (3)协程与管道
      • (4)只读只写管道的声明
      • (5)管道阻塞
    • 4.select功能
    • 5.defer+recover
  • 八、网络编程
    • 1.创建客户端
    • 2.创建服务器
    • 3.连接测试
    • 4.发送终端数据
  • 九、反射


一、基础

1.DOS命令

D: //转d盘
go build helloworld.go //编译.exe
go run helloworld.go //编译并执行.exe
// /**/ 注释

2.变量

(1)局部变量

var a int //声明变量
a = 10 //赋值
var b = 20 //自动类型推断
c := "qwq" //省略var
var d,e,f = 10 , "jack" , 3.14 //多变量声明,:=等也可

(2)全局变量

var (
	n1=1
	n2=2
) //多个声明

(3)数据类型

基本数据类型(数值型):

int , int8 , int16 , int32 , int64 , 
uint, uint8, uint16 , uint32 , uint64 , byte ,
float32 , float64 //可以用科学计数法如 314E-2

基本数据类型(字符型):无,使用

byte

基本数据类型(布尔型):

bool

基本数据类型(字符串):

string
"qwq" or 'q'//无特殊类型采用
`qwq`//有特殊类型采用
//+号拼接

复杂数据类型:指针、数组、结构体、管道、函数、切片、接口、map

类型转换(显式转换):同C++

(4)指针

&num //地址
var ptr *int = &num //指针定义
*ptr //获取地址对应的值,很像C++

(5)运算符

在这里插入图片描述

(6)自定义数据类型

相当于起别名,但是编译器不会认为起名前后是一种数据类型

type myInt int
type 

3.语句

(1)条件语句

类似C++

// if
if 布尔表达式 1 {
   /* 在布尔表达式 1 为 true 时执行 */
}
else if 布尔表达式2{
}
else{
}
// switch,注意:自带break
switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

// select


(2)循环语句

// 格式
for init; condition; post {
}
for condition {
}
// range示例
for key, value := range oldMap {
    newMap[key] = value
}
//无限循环
for true{
}
for ;;{
}
for {
}
break //类似
break label1 //将指定label的循环终止(可以是大循环)
continue //同C++
return 

4.函数

(1)基础

// 格式,函数名首字母大写,可以被本包和其他包文件使用;首字母小写,只能被本包使用
func function_name( [parameter list] ) [return_types] {
   函数体
}
// 示例,不返回值时,[return_types]是可以被省略的
func swap(x, y string) (string, string) {
   return y, x
}
func swap(x, y string) (y string, x string) {
   return
}

注意:go不支持函数重载

// 可变参数,可以传入任意个变量,传入变量当做切片来处理
func test(args...int){
}
// 地址传递,同C++
test(&num)
func test(num int*){
	*num = 10
}

函数也是一种数据类型,可以赋值给变量,通过该变量可以实现函数调用,函数可以做为形参。

a := test
a(10) //调用函数
// 函数可以作为形参
fun test2(testFunc func(int)){
}

(2)结构

说明:

func (目标形参名 绑定目标) 函数名(传入形参名 形参数据类型, 传入形参名 形参数据类型) ([返回的变量] 返回数据类型){
}
/* 常规函数 */
func 函数名(传入形参名 形参数据类型, 传入形参名 形参数据类型) ([返回的变量] 返回数据类型){
}
func 函数名(传入形参名 形参数据类型, 传入形参名 形参数据类型) {
}
/* 工厂模式 */
func 首字母大写函数名(传入形参名 形参数据类型, 传入形参名 形参数据类型) *结构体名{
}
/* 方法 */
func (目标形参名 绑定目标) 函数名(传入形参名 形参数据类型, 传入形参名 形参数据类型) ([返回的变量] 返回数据类型){
} // 值传递
func (目标形参名 *绑定目标) 函数名(传入形参名 形参数据类型, 传入形参名 形参数据类型) ([返回的变量] 返回数据类型){
} // 指针传递

示例:

// 定义一个后续需要的结构体
type person struct{
	Name string
	age int
}

/* 常规函数 */
func GetPerson(Name string, Age int ,Year int) (NewYear int){
	fmt.Println("正在计算" + Name + "现在的年龄")
	NewYear = Age + Year
	return
}
func GetPerson(Name string, Age int ,Year int) (int){
	fmt.Println("正在计算" + Name + "现在的年龄")
	NewYear = Age + Year
	return NewYear
}
func GetPerson(Name string) {
	fmt.Println("正在计算" + Name + "现在的年龄")
}
/* 工厂模式 */
func NewPerson(name string) *person{
	return &person{
		Name : name
	}
}
/* 方法 */
//与常规函数类似,只是多了一个绑定
func (p person) GetPerson(传入形参名 形参数据类型, 传入形参名 形参数据类型) ([返回的变量] 返回数据类型){
} // 值传递
func (p *person) 函数名(传入形参名 形参数据类型, 传入形参名 形参数据类型) ([返回的变量] 返回数据类型){
} // 指针传递,函数调用和结构体属性调用无需&或*

二、常用函数

0.基础

(1)len() 和 cap()

len同python,cap可以提供切片最长长度

(2)new()

num := new(int) // new的实参是一个类型,返回值是对应类型的指针

(3)make(Type, len, cap)

内存分配的内置函数:数据类型(slice,map,channel),长度(对于slice是必选),提前预留长度(可选)

(4)nil

判断数组时表示空

(5)append() 和 copy()

切片的追加和复制

num2 = append(num, 0) // 追加切片
num = copy(num2, num) // 把num的内容复制到num2,往往用于增加切片容量

(6)Range关键字

用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。

for key, value := range oldMap {
    newMap[key] = value
}
for key := range oldMap {
    newMap[key] = value
}
for key, _ := range oldMap {
    newMap[key] = value
}

(7)_

忽略作用

(8)element()

value, ok := element.(T)

value为变量的值
ok为bool类型
element是interface变量
T是断言类型

(9).(type)

type关键字,数据类型判断,与switch配合使用:

// 实现数据类型的判断
func checkType(i interface{}) string {
  switch i.(type) {
  case string:
    return "string"
  case int:
    return "int"
  case float64:
    return "float64"
  default:
    return "unknown"
  }
}

1.package unsafe

(1)unsafe.Sizeof(num)

返回类型尺寸

2.import “fmt”

(1)输出

Printf("it is %T",num) //格式化输出
Println(num) //直接输出,相邻参数间添加空格
Print("num") //直接输出,相邻非字符串间添加空格
str = Sprintf("it is %T",num) //可以保存字符串
var num2 string = fmt.Sprintf("qwq %d",num) //将num转为string

(2)输入

Scanln(&num) //获取输入,必须是地址,类型需要匹配
Scanf("%d %s" , &age , &name) //获取输入,多个输入,输入需要空格相间

在这里插入图片描述

3.import “strconv”

在这里插入图片描述

注意:也可用Sprintf()实现同样功能

在这里插入图片描述
注意:无效值会被转为默认值

4.字符串函数

strconv 和 strings
在这里插入图片描述
rune 类似 int32,以此方式遍历更兼容汉字

在这里插入图片描述
在这里插入图片描述

5.import “os”

在这里插入图片描述

6.import “io”

7.import “io/ioutil”

8.import “bufio”

9.import “sync”

三、包及其函数

1.包的引入

建议包(package)的声明和文件夹名一致,函数首字母必须大写。同一目录下包名必须一致

import "文件夹路径" //import引入
import ( //多个包导入
	"fmt"
	test "gocode/testproject01/demo01" //起别名,用于调用
)
包名.函数名 //调用

2.init函数

优先级:全局变量>其他包的init>本包的init>main,用法和main差不多

3.匿名函数与闭包

只被用一次的函数,也可以定义为全局的
在这里插入图片描述
闭包,对内存消耗大:

func getSum() func (int) int {
	var sum int = 10
	return func (num int) int{ //匿名函数,该函数引用的变量会一直保存在内存中,可以一直使用
		sum = sum + num
		return sum
	}
}
// 闭包:返回的匿名函数+匿名函数以外的变量sum
func main(){
	f := getSum()
	fmt.Println(f(1)) //11 传参到匿名函数
}

4.defer关键字

把defer后的语句压入栈中

defer Println("qwq") //函数截止时执行并释放

5.日期和时间函数

import "time"
now := time.Now() //获取当前时间,返回一个结构体

在这里插入图片描述

详情见 https://studygolang.com/pkgdoc

6.错误处理

(1)错误捕获

defer func(){ //捕获错误,使得程序可以继续
	err := recover()
	if err != nil{
		...
	}
}() //加括号用于调用

(2)自定义错误

import "errors"
err := errors.New("报错...") //报错,并继续运行

panic(err) //报错,并终止运行

四、数组、切片、映射

1.数组

数组声明

// 一维数组
var numbers = [5]int{1, 2, 3, 4, 5}
numbers := [5]int{1, 2, 3, 4, 5}
var numbers = [...]int{1, 2, 3, 4, 5}
numbers := [...]int{1:20, 4:99, 3:25}
// 多维数组
var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type //格式
var arr = [2][3]int{{1,4,7},{2,5,8}}
var arr [2][3]int = [2][3]int{{1,4,7},{2,5,8}}

形参数组

func myFunction(param []int) { //未设定数组大小
    ....
}
func myFunction(param [10]int) { //固定数组大小
    ....
}

2.切片 []

var s = []int{1,2,3,4 } //声明方式
s :=[] int {1,2,3 } 
var s[]type = make([]type, len) //采用make的声明方式
s := make([]type, len)

arr = s[startIndex:endIndex] // 类似python,包含左不包含右

切片的切片发生变动时,原切片也会发生改变;
参见append() 和 copy()

3.集合/字典/映射 Map

// 使用 make 函数
m := make(map[KeyType]ValueType, initialCapacity)
// 使用字面量创建 Map
m := map[string]int{
    "apple": 1,
    "banana": 2,
    "orange": 3,
}
// 删除键值对
delete(m, "banana")
//查询相关映射是否存在
value, flag := m[orange]

五、面向对象

1.结构体

(1)基础

类似C++,但是golang没有类(class),无重载、构造函数、析构函数、隐藏的this指针等;
但仍有继承、封装、多态等特性

type Books struct {
   title string
   author string
   subject string
   book_id int
}

variable_name := Books {value1, value2...valuen} //声明变量
或
variable_name := Books { key1: value1, key2: value2..., keyn: valuen}

结构体.成员名 //访问方式

对于结构体指针,直接指针名加“.”来调用

struct_pointer.title

在这里插入图片描述
有指针的简化赋值,特别是在“方法”中, & t . 属性 \&t.属性 &t.属性 ∗ t . 属性 *t.属性 t.属性 都可以简写为 t . 属性 t.属性 t.属性

(2)转换

两个结构体的名字、个数和类型必须一致,需要运用强制类型转换。

(3)方法的引入

作用在指定数据类型,不仅是适用于struct的。可以为结构体等设置专用函数

type Person struct{
	Name string
}
func (p Person) test(){ //方法的绑定
	fmt.Println(p.Name)
}
func main(){
	var p Person
	p.Name = "丽丽"
	p.test()
}

//其他类型的绑定
type integer int
func (i integer) print(){ //方法的绑定
	fmt.Print1n("i = ",i)
}
func main(){
	var i integer = 20
	i.print()
}

注意:

  • test方法中参数名字随意起。
  • 结构体Person和test方法绑定,调用test方法必须靠指定的类型: Person。
  • 如果其他类型变量调用test方法一定会报错。
  • 结构体对象传入test方法中,值传递,和函数参数传递一致。

(4)方法与函数的差别

  • 绑定指定类型:
    方法:需要绑定指定数据类型
    函数:不需要绑定数据类型
  • 调用方式不一样:
    函数的调用方式:
    函数名(实参列表)
    方法的调用方式:
    变量.方法名(实参列表)
  • 对于函数来说,参数类型对应是什么就要传入什么。
  • 对于方法来说,接收者为值类型,可以传入指针类型,接受者为指针类型,可以传入值类型。(都是传值)

(5)创建结构体实例

本包

type Student struct{
	Name string
	Age int
}

func main(){
	var s1 = Student{"Ann", 19} // 按顺序赋值
	var s2 = Student{ // 按类型赋值
		Age : 20,
		Name : "郭哲炜",
	}
	// 想要返回结构体的指针类型
	var s3 = &Student{"Ann", 19}
	var s4 = &Student{
		Age : 20,
		Name : "郭哲炜",
	}
}

跨包
结构体首字母大写,可以跨包访问;
如果小写,则需要引入工厂模式。

// 在非main包中
import "文件夹路径/model"
	/* 首字母大写 */
type Student struct{
	Name string
	Age int
}
s = model.Student{"lili",10}

	/* 首字母小写 */
type student struct{
	Name string
	Age int
}
		// 工厂模式 
func NewStudent(n string, a int) *student{
	return &student{n, a}
}

2.封装

封装的引入:
(1)建议将结构体、字段(属性)的首字母小写(大写其实也行)
(2)给结构体所在包提供一个工厂模式的函数,首字母大写(类似构造函数)
(3)提供一个首字母大写的Set方法,用于对属性判断并赋值
(4)提供一个首字母大写的Get方法,用于获取属性的值

封装的实现:

type person struct{
	Name string
	age int // 小写的,别的包不能直接访问
} 
// 工厂模式函数
func NewPerson(name string) *person{
	return &person{
		Name : name
	}		
}
// 定义 Set和 Get "方法"
func (p *person) SetAge(age int){
	if age > 0 && age < 150{
		p.age = age
	} else {
		fmt.Println("您输入的年龄有误")
	}
}
func (p *person) GetAge() int{
	return p.age
}

3.继承

(1)基础

如果一个结构体嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法。从而实现了继承特性。

type Animal struct{
	Age int
	Weight float32
}
// 绑定方法
func (an *Animal) Shout(){
	fmt.Println("啊啊啊啊啊啊啊啊")
}
func (an *Animal) ShowInfo(){
	fmt.Println("年龄为: %v,体重为: %v", an.Age, an.Weight)
}
// 定义新结构体
type Cat struct{
	Animal
}
// 绑定特有方法
func (c *Cat) scratch(){
	fmt.Println("喵喵喵,挠你")
}

func main(){
	Cat.Animal.Age = 3
}

(2)注意事项

(1)结构体可以使用嵌套的匿名结构体所有字段和方法(不受首字母影响)。
(2)匿名结构体字段访问可以简化。
(3)结构体和匿名结构体有相同的字段或方法时,使用简化版本时,编译器就近原则。

func main(){
	Cat.Age = 3
}

(4)存在多继承(但不建议使用)
(5)匿名结构体有相同字段时,不能简化,以区分
(6)结构体的匿名字段可以是基本类型
(7)嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值。
(8)嵌入匿名结构体的指针也是可以的。
(9)结构体的字段可以是结构体类型的。(组合模式)

4.接口

(1)基础

(1)接口中定义一组方法,无需实现,不能有变量。
(2)所有方法都必须实现,才算接口。
(3)Golang没有显式的接口关键字。
(4)接口的目的是定义规范。

//接口的定义
type Say interface{
	sayHello()
}
//接口的实现
type Chinese struct{
}
func (person Chinese) sayHello(){
	fmt.Println("你好")
}
type American struct{
}
func (person American) sayHello(){
	fmt.Println("hi")
}
//接口接收函数
func greet(s Say){ // 多态是基于接口实现的
	s.sayHello()
}

func main(){
	c := Chinese{}
	a := American{}
	greet(a) // 函数方式调用接口
	greet(c)
	var s Say = a // 指向方法调用接口
	s.sayHello()
	var s Say = c
	s.sayHello()
}

(2)注意事项

(1)接口本身不能创建实例,但可以指向一个实现了该接口的自定义类型的变量
(2)只要是自定义类型变量,就可以实现接口,不仅仅是struct

// 基于上边的代码
type integer int // 自定义的类型
func (i integer) sayHello(){
	fmt.Println(i)
}
func main(){
	var i integer = 10
	var s Say = i // 会输出打印
	s.sayHello
}

(3)一个自定义类型可以实现多个接口

//与上述代码无关
type CInterface interface{
	c()
}
type BInterface interface{
	b()
}
type AInterface interface{
	CInterface
	BInterface
	a()
}
func ...// a(), b(), c() 三个方法都需要被实现

(4)一个接口可以继承多个别的接口
(5)interface类型默认是一个指针(引用类型),默认为nil
(6)空接口没有任何方法:所有类型都实现了空接口,任何一个类型的变量都可以赋值给空接口。

type E interface{
}

(3)多态

多态是基于接口实现的,参考上文(1)中的代码

func greet(s Say){ // 多态是基于接口实现的
	s.sayHello()
}

(1)多态参数:如之前的例子
(2)多态数组:定义Say数组,可以存放Chinese结构体、American结构体

//接口的定义
type Say interface{
	sayHello()
}
//接口的实现
type Chinese struct{
	name string
}
func (person Chinese) sayHello(){
	fmt.Println("你好")
}
type American struct{
	name string
}
func (person American) sayHello(){
	fmt.Println("hi")
}
//接口接收函数
func greet(s Say){ // 多态是基于接口实现的
	s.sayHello()
}

func main(){
	var arr [3]Say
	arr[0] = American{"Ann"}
	arr[1] = Chinese{"郭哲炜"}
	arr[2] = American{"Peter"}
	fmt.Println(arr)
}

6.断言

//接口的定义
type Say interface {
	sayHello()
}

//接口的实现
//中国人
type Chinese struct {
	name string
}
func (person Chinese) sayHello() {
	fmt.Println("你好")
}
func (person Chinese) kuaizi() { //专有函数
	fmt.Println("筷子")
}

//美国人
type American struct {
	name string
}
func (person American) sayHello() {
	fmt.Println("hi")
}
func (person American) hpop() { //专有函数
	fmt.Println("Hpop")
}

//接口接收函数,断言实现
func greet(s Say) { // 多态是基于接口实现的
	s.sayHello()
	/*断言写法1:if判断*/
	if value, ok := s.(Chinese); ok {
	value.kuaizi()
	} else {
	fmt.Println("美国人不用筷子")
	}
	/*断言写法2:switch判断*/
	switch s.(type) {
	case Chinese:
		temp := s.(Chinese)
		temp.kuaizi()
	case American:
		temp := s.(American)
		temp.hpop()
	default:
		fmt.Println("未知的类型")
	}

}

func main() {
	c := Chinese{"郭哲炜"}
	a := American{"Peter"}
	greet(a)
	greet(c)
}

六、文件操作

1.文件

打开和关闭文件:

import (
	"os"
	"fmt"
)

func main(){
	//打开文件
	file, err := os.Open("d:/Test.txt")
	if err != nil{ //出错
		fmt.Println("文件出错,问题为:",err)
	}
	//没有出错,输出文件
	fmt.Printf("文件=%v",file)
	
	/*关闭文件 方法1*/
	err2 := file.Close();
	}
		if err2 != nil{ //出错
			fmt.Println("关闭失败")
	}

2.io读取文件

内含有Open和Close的函数的操作:

import (
	"fmt"
	"io/ioutil"
)

func main(){
	//读取文件:
	content, err = ioutil.ReadFile("d:/Test.txt") //返回内容为[]byte,err
		if err != nil{ //出错
		fmt.Println("读取出错",err)
		}
		//成功
		fmt.Printf("%v",string(content))		
}

不内含有Open和Close的函数的操作(推荐):

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func main() {
	//打开文件
	file, err := os.Open("d:/Test.txt")
	if err != nil { //出错
		fmt.Println("文件出错,问题为:", err)
	}
	/*关闭文件 方法2*/
	defer file.Close()

	//创建一个流
	reader := bufio.NewReader(file)
	//读取方法
	for {
		str, err := reader.ReadString('\n') //读到换行截止

		fmt.Println(str)
		if err == io.EOF {
			break
		}
	}
}

3.io写入文件

函数:

func OpenFile(name string, flag int, perm FileMode) (file *File, err error)

(1)参数一:文件路径
(2)参数二:文件打开模式(用“|”组合)

const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
    O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
    O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
    O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件
    O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用,文件必须不存在
    O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O
    O_TRUNC  int = syscall.O_TRUNC  // 如果可能,打开时清空文件
)

(3)权限控制(linux/unix才生效)

import(
	"fmt"
	"os"
	"bufio"
)
func main(){
	//打开文件
	file, err := os.OpenFile(d:/Demo.txt, os.O_RDWR | os.O_APPEND | os.O_CREATE, 0666)
	if err != nil{
		fmt.Println("打开文件失败", err)
		return
	}
	//关闭文件
	defer file.Close()
	//写入文件:IO流→缓冲输出流(带缓冲区)
	writer := bufio.NewWriter(file)
	for i := 0; i < 10; i++{
	writer.WriteString("你好 郭哲炜\n")
	}

	//流带缓冲区,刷新数据→真正地写入文件中:
	writer.Flush()
}

4.文件复制操作

读取+写入(不推荐使用ioutil):

import(
	"fmt"
	"io/ioutil"
)
func main(){
	//定义源文件
	file1 := "d:/Demo.txt"
	//定义目标文件
	file2 := "d:/Demo2.txt"
	
	//对文件进行读取
	content, err := ioutil.ReadFile(file1)
	if err != nil{
	fmt.Println("读取失败")
	return
	}
	//写出文件
	err2 = ioutil.WriteFile(file2,content,0666)
	if err2 != nil{
	fmt.Println("写出失败")
	return
	}

七、协程和管道

1.基本概念

(1)程序

是为了完成特定任务,用某种语言编写的一组指令的集合,是一段静态的代码。

(2)进程

是程序的一次执行过程,进程作为资源分配的单位,在内存中会为每个进程分配不同的内存区域。它是动态的,有自身产生、存在和消亡的过程。

(3)线程

进程可进一步细化为线程,是一个程序内部的一条执行路径。

(4)协程

又称为微线程,是一种用户态的轻量级线程。

2.协程

(1)多协程

协程可以多个,但是主程序结束时,协程也会跟着结束。

func main(){
	//启动多个协程
	for i := 1; i <= 5; i++{
		go func(){
			fmt.Println("hello world")
		}()
	}
}

(2)延长协程存活

延长协程的存活时间 sync.WaitGroup

import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup //只定义无需赋值
func main(){
	//启动多个协程
	for i := 1; i <= 5; i++{
		wg.Add(1) //协程开始时加一
		go func(){
			fmt.Println("hello world")
			defer wg.Done() //协程结束时减一,可以结合defer使用
			}()
	}
	//主线程一直在阻塞,什么时候wg减为0,则停止
	wg.Wait()
}

(3)互斥锁同步协程

解决多个协程操作一个数据,结果混乱的情况。但互斥锁效率比较低

import (
	"fmt"
	"sync"
)
var totalNum int
var wg sync,WaitGroup
//互斥锁
var lock sync.Mutex
func add(){
	defer wg.Done()
	for i := 0; i < 1000; i++{
		//加锁
		lock.Lock()
		totalNum = totalNum + 1
		//解锁
		lock.Unlock()
	}
}
func sub(){
	defer wg.Done()
	for i := 0; i < 1000; i++{
		//加锁
		lock.Lock()
		totalNum = totalNum - 1
		//解锁
		lock.Unlock()
	}
}
func main(){
	wg.Add(2) //启动协程
	go add()
	go sub()
	wg.Wait() //阻塞主进程
	fmt.Println(totalNum)
}

(4)读写锁

写和读之间才会产生影响,单单在读的时候不会彼此产生影响。

import (
	"fmt"
	"sync"
	"time"
)
var totalNum int
var wg sync,WaitGroup
//互斥锁
var lock sync.RWMutex
func read(){
	defer wg.Done()
	lock.RLock() //如果只是读数据,则这个锁不会产生影响,同时读写则会有影响
	fmt.Println("开始读取数据")
	time.Sleep(time.Second)	
	fmt.Println("读取数据完毕")
	lock.RUnlock()
}
func sub(){
	defer wg.Done()
	lock.Lock() //如果只是读数据,则这个锁不会产生影响,同时读写则会有影响
	fmt.Println("开始写入数据")
	time.Sleep(time.Second*10)	
	fmt.Println("写入数据完毕")
	lock.Unlock()
}
func main(){
	wg.Add(2) //启动协程
	for i := 0; i < 5; i++{
		go read()
	}	
	go write()
	wg.Wait() //阻塞主进程
}

3.管道

本质是数据结构里的队列,先进先出,线程安全无需加锁。
管道是有类型的,一个string的管道只能放string类型。

var intChan chan int //声明定义
intChan = make(chan int, 3) //初始化空间
intChan <- 10 //存放数据
num := <- intChan //取出数据

在没有使用协程的情况下,如果数据已经全部取出,再取会报错(不能放多,不能取多)

(1)管道关闭

可以取,不可放。

close(intChan)

(2)管道遍历

(3)协程与管道

(4)只读只写管道的声明

(5)管道阻塞

4.select功能

5.defer+recover

八、网络编程

1.创建客户端

2.创建服务器

3.连接测试

4.发送终端数据

九、反射

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/618197.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Navicat 干货 | 探索 PostgreSQL 中不同类型的约束

PostgreSQL 的一个重要特性之一是能够对数据实施各种约束&#xff0c;以确保数据完整性和可靠性。今天的文章中&#xff0c;我们将概述 PostgreSQL 的各种约束类型并结合免费的 "dvdrental" 示例数据库 中的例子探索他们的使用方法。 1. 检查约束&#xff1a; 检查…

Virtualbox7.0.10+Ubuntu20.04网络配置

虚拟机部署在服务器上时&#xff0c;需要进行网络配置&#xff0c;使虚拟机和服务器在同网段下&#xff0c;以保证内网的终端可以访问到虚拟机 1. 设置虚拟机 打开虚拟机设置&#xff0c;选择“网络”&#xff0c;将网卡设为桥接网卡 注&#xff1a;设置前&#xff0c;需要先…

[通用人工智能] 论文分享:ElasticViT:基于冲突感知超网的快速视觉Transformer

引言: 近年来&#xff0c;视觉Transformer&#xff08;Vision Transformer&#xff0c;简称ViT&#xff09;在计算机视觉任务中的应用日益广泛&#xff0c;从图像分类到对象识别等&#xff0c;均显示出优越的性能。然而&#xff0c;ViT模型也面临一些挑战&#xff0c;特别是在模…

抽丝剥茧:详述一次DevServer Proxy配置无效问题的细致排查过程

事情的起因是这样的&#xff0c;在一个已上线的项目中&#xff0c;其中一个包含登录和获取菜单的接口因响应时间较长&#xff0c;后端让我尝试未经服务转发的另一域名下的新接口&#xff0c;旧接口允许跨域请求&#xff0c;但新接口不允许本地访问&#xff08;只允许发布测试/生…

ARM架构安全特性概览

安全之安全(security)博客目录导读 目录 一、跨行业计算安全 二、Arm架构安全特性的益处 三、安全威胁与缓解 四、防御执行技术 五、隔离技术 六、通用平台安全服务 七、标准安全 API 八、PSA安全标准认证 一、跨行业计算安全 从一开始&#xff0c;Arm 生态系统一直是…

VS项目Debug下生成的EXE在生产机器上运行

使用Visual Studio开发应用程序时&#xff0c;为了临时在非开发机上看一下效果&#xff0c;就直接把Debug下的文件全部拷贝到该机器上&#xff0c;直接双击exe运行。双击之后&#xff0c;没有直接打开应用程序&#xff0c;而是弹出了一个Error弹框。  赶快在网上搜了一遍&…

Ardupilot开源代码之Rover上路 - 后续1

Ardupilot开源代码之Rover上路 - 后续1 1. 源由2. 问题汇总2.1 问题1&#xff1a;飞控选择2.2 问题2&#xff1a;飞控安装位置和固定2.3 问题3&#xff1a;各种插头、插座配套2.4 问题4&#xff1a;分电板缺陷2.5 问题5&#xff1a;电机编码器接线及正反向问题2.6 问题6&#x…

什么是等保2.0,相对等保1.0有哪些变化,支撑等保2.0的标准文档有哪些?

1. 等保1.0、等保2.0业界定义 等保1.0&#xff1a;以1994年2月18日年国务院颁布的 147 号令《中华人民共和国计算机信息系统安全保护条例》为指导标准&#xff0c;以2008年发布的《GB/T22239-2008 信息安全技术 信息系统安全等级保护基本要求 》为指导的网络安全等级保护办法。…

向量数据库:Chroma

目录 一、Chroma 介绍 二、安装 Chroma 2.1 创建虚拟 python 环境 2.2 安装 Chroma 2.3 运行 Chroma 三、Backend API 一、Chroma 介绍 Chroma是一个开源的嵌入式数据库。Chroma通过使知识(knowledge)、事实(facts)和技能(skills)可插拔&#xff0c;从而简化了大型语言模…

小猫咪邮件在线发送系统源码,支持添加附件

一款免登录发送邮件&#xff0c;支持发送附件&#xff0c;后台可添加邮箱,前台可选择发送邮箱 网站数据采取本地保存&#xff0c;所以使用前请给网站修改权限&#xff0c;否则很多功能将无法使用 安装教程&#xff1a; 1.上传服务器或者主机 2.登录后台&#xff0c;添加发送…

FCOS长文详解

1. 概述 FCOS是一种one-stage、全卷积&#xff08;Fully Convolutional&#xff09;结构的目标检测模型&#xff0c;发表于2019年ICCV。&#xff08;什么是one-stage&#xff1f;&#xff09; 论文原地址&#xff1a;https://arxiv.org/abs/1904.01355 作者源码&#xff1a;ht…

本地项目上传到gitee

1. 新建仓库&#xff0c;不要勾选 2. git init git add . git commit -m "test" git remote add origin 【url】 git push --set-upstream origin master

【Java】:方法重写、动态绑定和多态

目录 一个生动形象的例子 场景设定 1. 方法重写&#xff08;Method Overriding&#xff09; 2. 动态绑定&#xff08;Dynamic Binding&#xff09; 3. 多态&#xff08;Polymorphism&#xff09; 归纳关系&#xff1a; 重写 概念 条件 重写的示例 重载与重写的区别 …

STM32 | STC-USB驱动安装Windows 10(64 位)

Windows 10&#xff08;64 位&#xff09;安装方法 由于 Windows10 64 位操作系统在默认状态下&#xff0c;对于没有数字签名的驱动程序是不能安装成功的。所以在安装 STC-USB 驱动前&#xff0c;需要按照如下步骤&#xff0c;暂时跳过数字签名&#xff0c;即可顺利安装成功。…

回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测

回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测 目录 回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现GA-LSSVM遗传算法优化最小…

纯CSS实现步骤条

纯CSS实现纵向Steps步骤条效果 效果图 实现思路 步骤条是一种用于引导用户按照特定流程完成任务的导航条&#xff0c;在各种分步表单交互场景中广泛应用。步骤条通常由编号、名称和引导线三个基本要素组成。本文中要实现的是一个简单的步骤条&#xff0c;包含上述三个基本要素…

Python爬虫实战:爬取【某旅游交通出行类网站中国内热门景点】的评论数据,使用Re、BeautifulSoup与Xpath三种方式解析数据,代码完整

一、分析爬取网页&#xff1a; 1、网址 https://travel.qunar.com/2、 打开网站&#xff0c;找到要爬取的网页 https://travel.qunar.com/p-cs299979-chongqing进来之后&#xff0c;找到评论界面&#xff0c;如下所示&#xff1a;在这里我选择驴友点评数据爬取点击【驴友点评…

天下大爱唯母爱

岁月轮转&#xff0c;人生寻常&#xff0c;又逢一年母亲节。作为子女&#xff0c;这是所有人都参与节日&#xff0c;也是每一位母亲在繁忙日常中&#xff0c;一个短暂的休息&#xff0c;停下手中的忙碌&#xff0c;听孩子的一声祝福&#xff1a;妈妈辛苦了&#xff0c;母亲节快…

树莓派4B-搭建一个本地车牌识别服务器

实现目标&#xff1a; 一、设备自启后能够获得服务的ip与端口号&#xff0c;用于计算机连接设备&#xff1b; 二、计算机可以通过服务ip与端口访问设备服务&#xff1b; 三、上传需要处理的数据&#xff0c;返回结果反馈给用户&#xff1b; 四、上传到服务器的数据不会导致设备…

车载测试系列:CAPL脚本语法

HFP测试内容与测试方法 2.3 接听来电&#xff1a;测试手机来电时&#xff0c;能否从车载蓝牙设备和手机侧正常接听】拒接、通话是否正常。 1、预置条件&#xff1a;待测手机与车载车载设备处于连接状态 2、测试步骤&#xff1a; 1&#xff09;用辅助测试机拨打待测手机&…