Go基础部分总结4

1.文件的打开与关闭
输入:

package main

import (
	"fmt"
	"os"
)

func main() {
	//Open()函数
	open, err := os.Open("E:/GO/notepad/0630/GoTest.txt")
	//文件打开出错
	if err != nil {
		fmt.Println("open file err:", err)
	} else {
		fmt.Println("open file is:", open)
		//Close()方法
		errClose := open.Close()
		if errClose != nil {
			fmt.Println("errClose:", errClose)
		}
		fmt.Println("open file is closed")
	}
}

输出:

open file is: &{0xc00006ca08}
open file is closed

2.ReadFile方法的使用(一次性读取的方式)
输入:

package main

import (
	"fmt"
	"os"
)

func main() {
	//使用ReadFile方法,不需要再进行Open,Close,方法内部已经进行封装
	file, err := os.ReadFile("E:/GO/notepad/0630/GoTest.txt")
	if err != nil {
		fmt.Println("Error:", err)
	}
	fmt.Println(file)         //直接输出(字节类型)
	fmt.Println(string(file)) //转成字符类型输出
}

输出:

[72 111 108 100 32 111 110]
Hold on

3.带缓冲的读取bufio.NewReader(file)

package main

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

func main() {
	file, err := os.Open("E:/GO/notepad/0630/GoTest.txt")
	if err != nil {
		fmt.Println("err=", err)
	}
	//所有程序执行完成后,进行文件的关闭
	defer file.Close()
	//创建文件流   利用NewReader(file)方法
	buf := bufio.NewReader(file)
	//进行读取操作
	for {
		readString, err := buf.ReadString('\n') //读取到 换行(字符用单引号) 结束读取
		if err == io.EOF {
			fmt.Println("文件读取完成")
			break
		}
		fmt.Print(readString)
	}
}

4.写入文件
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 // 如果可能,打开时清空文件
)
输入:

package main

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

func main() {
	//最后的0666在windows中设置不生效,在Linux中生效
	//os.O_RDWR文件读写
	//os.O_APPEND表示新添加的内容在原文件上进行追加
	//os.O_CREATE表示如果文件不存在,进行创建
	openFile, err := os.OpenFile("E:/GO/notepad/0630/GoTest2.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	s := os.FileMode(0666).String()
	fmt.Println(s) //输出在Linux中的执行权限
	if err != nil {
		fmt.Println("err=", err)
		return
	}
	defer openFile.Close()
	//缓冲输入流
	buf := bufio.NewWriter(openFile)
	for i := 0; i < 10; i++ {
		buf.WriteString("Hello xx\n")
	}
	//刷新数据
	buf.Flush()
}

在这里插入图片描述
5.文件的复制
输入:

package main

import (
	"fmt"
	"os"
)

func main() {
	//定义源文件
	file, err := os.ReadFile("E:\\GO\\notepad\\0630\\GoTest2.txt")
	if err != nil {
		fmt.Println("Error:", err)
	}
	//写入文件
	err = os.WriteFile("E:\\GO\\notepad\\0630\\GoTest3.txt", file, 0644)
	if err != nil {
		fmt.Println("Error:", err)
	}
}

在这里插入图片描述
6.协程(实现多线程)
输入:

package main

import (
	"fmt"
	"time"
)

func test() {
	for i := 0; i < 10; i++ {
		fmt.Println("函数中的线程-----", i)
		//阻塞一秒
		time.Sleep(time.Second)
	}
}

func main() {
	go test() //开启协程
	for i := 0; i < 10; i++ {
		fmt.Println("主线程中的线程-----", i)
		//阻塞一秒
		time.Sleep(time.Second)
	}
}

输出:

主线程中的线程----- 0
函数中的线程----- 0
函数中的线程----- 1
主线程中的线程----- 1
函数中的线程----- 2
主线程中的线程----- 2
函数中的线程----- 3
主线程中的线程----- 3
函数中的线程----- 4
主线程中的线程----- 4
主线程中的线程----- 5
函数中的线程----- 5
函数中的线程----- 6
主线程中的线程----- 6
主线程中的线程----- 7
函数中的线程----- 7
函数中的线程----- 8
主线程中的线程----- 8
主线程中的线程----- 9
函数中的线程----- 9

7.主死协从
主线程结束后,协程也立即结束
输入:

package main

import (
	"fmt"
	"time"
)

func test() {
	for i := 0; i < 10; i++ {
		fmt.Println("函数中的线程-----", i)
		//阻塞一秒
		time.Sleep(time.Second)
	}
}

func main() {
	go test() //开启协程
	for i := 0; i < 3; i++ {
		fmt.Println("主线程中的线程-----", i)
		//阻塞一秒
		time.Sleep(time.Second)
	}
}

输出:

主线程中的线程----- 0
函数中的线程----- 0
主线程中的线程----- 1
函数中的线程----- 1
函数中的线程----- 2
主线程中的线程----- 2

8.多协程
输入:

package main

import (
	"fmt"
	"time"
)

func main() {
	for i := 0; i < 5; i++ {
		//匿名函数
		go func(n int) {
			fmt.Println("Hello World,", i)
		}(i)
	}
	//防止主线程直接结束
	time.Sleep(time.Second * 3)
}

输出:

Hello World, 4
Hello World, 0
Hello World, 2
Hello World, 1
Hello World, 3

9.WaitGroup
WaitGroup用于等待一组线程的结束。父线程调用Add方法来设定应等待的线程的数量。每个被等待的线程在结束时应调用Done方法。同时,主线程里可以调用Wait方法阻塞至所有线程结束。
输入:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {
	for i := 0; i < 5; i++ {
		wg.Add(1) //协程开始时加一
		go func(n int) {
			defer wg.Done() //协程结束时减一
			fmt.Println(n)
		}(i)
	}
	//协程结束前进行阻塞
	wg.Wait()
}

输出:

4
2
1
3
0

10.互斥锁
Mutex是一个互斥锁,可以创建为其他结构体的字段;零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。

func (*Mutex) Lock
func (m *Mutex) Lock()
Lock方法锁住m,如果m已经加锁,则阻塞直到m解锁。

func (*Mutex) Unlock
func (m *Mutex) Unlock()
Unlock方法解锁m,如果m未加锁会导致运行时错误。锁和线程无关,可以由不同的线程加锁和解锁。
输入:

package main

import (
	"fmt"
	"sync"
)

var account = 0
var wg = sync.WaitGroup{}
var l sync.Mutex //互斥锁

// 账户存钱函数
func save() {
	defer wg.Done()
	for i := 0; i < 10; i++ {
		l.Lock() //上锁
		account = account + i
		l.Unlock() //去锁
	}
}

// 账户取钱函数
func draw() {
	defer wg.Done()
	for i := 0; i < 10; i++ {
		l.Lock() //上锁
		account = account - i
		l.Unlock() //去锁
	}
}
func main() {
	wg.Add(1)
	save()
	wg.Add(1)
	draw()
	wg.Wait()
	fmt.Println(account)
}

输出:

0

11.读写锁
RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯一个写入者持有。RWMutex可以创建为其他结构体的字段;零值为解锁状态。RWMutex类型的锁也和线程无关,可以由不同的线程加读取锁/写入和解读取锁/写入锁。

func (*RWMutex) Lock
func (rw *RWMutex) Lock()
Lock方法将rw锁定为写入状态,禁止其他线程读取或者写入。

func (*RWMutex) Unlock
func (rw *RWMutex) Unlock()
Unlock方法解除rw的写入锁状态,如果m未加写入锁会导致运行时错误。

func (*RWMutex) RLock
func (rw *RWMutex) RLock()
RLock方法将rw锁定为读取状态,禁止其他线程写入,但不禁止读取。

func (*RWMutex) RUnlock
func (rw *RWMutex) RUnlock()
Runlock方法解除rw的读取锁状态,如果m未加读取锁会导致运行时错误。
输入:

package main

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup
var l sync.RWMutex // 读写锁
func read() {
	defer wg.Done()
	l.RLock() //读取上锁,此时禁止其他线程写入
	fmt.Println("执行读取")
	time.Sleep(2 * time.Second)
	fmt.Println("读取结束")
	l.RUnlock()
}
func write() {
	defer wg.Done()
	l.Lock() //Lock方法将rw锁定为写入状态,禁止其他线程读取或者写入。
	fmt.Println("执行写入")
	time.Sleep(5 * time.Second)
	fmt.Println("写入结束")
	l.Unlock()
}
func main() {
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go read()
	}
	go write()
	wg.Wait()
}

输出:

执行写入
写入结束
执行读取
执行读取
执行读取
执行读取
执行读取
读取结束
读取结束
读取结束
读取结束

12.管道
特点:
(1)管道本质就是一个队列(先进先出)
(2)自身线程安全,多协程访问时,不需要加锁,channel本身就是线程安全的
(3)管道有类型的,一个string的管道只能存放string类型数据

定义管道并初始化
输入:

func main() {
	//定义一个管道
	var intChan chan int
	var strChan chan string
	//通过make()方法进行初始化
	intChan = make(chan int)
	strChan = make(chan string)
	//管道为引用数据类型
	fmt.Printf("intChan => %v\n", intChan)
	fmt.Printf("strChan => %v\n", strChan)
}

13.管道的关闭

package main

import "fmt"

func main() {
	var intChin chan int
	//定义缓冲通道
	intChin = make(chan int, 5)
	//向管道中存入数据
	intChin <- 1
	intChin <- 2
	//管道关闭
	close(intChin)
	//读取管道数据
	fmt.Println(<-intChin)//读取正常
	fmt.Println(<-intChin)//读取正常
	//继续存入
	intChin <- 3 //这里报错
}

输出:

1
2
panic: send on closed channel

goroutine 1 [running]:
main.main()

14.管道的遍历
输入:

package main

import "fmt"

func main() {
	var intChain chan int
	intChain = make(chan int, 5)
	intChain <- 1
	intChain <- 2
	intChain <- 3
	//进行管道的遍历时,必须进行管道的关闭,否则会报错
	close(intChain)
	for v := range intChain {
		fmt.Println("v ==> ", v)
	}
}

输出:

v ==>  1
v ==>  2
v ==>  3

15.协程与管道的使用
输入:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

// 定义写入管道的函数
func write(intCh chan int) {
	defer wg.Done()
	for i := 0; i < 5; i++ {
		fmt.Println("write ==> ", i)
		intCh <- i
	}
	close(intCh) //防止出现死锁现象(未存储数据,先读导致)
}

// 定义读取管道的函数
func read(intCh chan int) {
	defer wg.Done()
	for v := range intCh {
		fmt.Println("read ==> ", v)
	}
}
func main() {
	var intChan chan int
	intChan = make(chan int, 10) // 定义无缓冲通道
	//防止主线程直接结束
	wg.Add(2)
	//定义协程
	go write(intChan)
	go read(intChan)
	wg.Wait()
}

输出:

write ==>  0
write ==>  1
write ==>  2
write ==>  3
write ==>  4
read ==>  0
read ==>  1
read ==>  2
read ==>  3
read ==>  4

16.只读管道与只写管道
输入:

package main

import "fmt"

func main() {
	//定义只写管道类型
	var inChan1 chan<- int //管道inChan1类型不变,只是增加了只读属性
	inChan1 = make(chan int, 5)
	inChan1 <- 1
	/**
	fmt.Println(<-inChan1) 爆红
	*/
	//定义只读管道类型
	var inChan2 <-chan int
	fmt.Println(inChan2)
	//fmt.Println(<-inChan2) 输出报错
}

输出:

<nil>

17.select关键字
在Go语言中,select 语句是一种特殊的语句,用于同时等待多个通信操作。当多个goroutine需要同时等待多个通信操作(如多个channel的发送或接收)时,select 语句就非常有用。select 会阻塞,直到某个分支可以继续执行为止(即某个channel可以进行发送或接收操作),然后执行那个分支。如果多个channel都准备好了,select 会随机选择一个执行。

select 语句的语法类似于switch,但每个case代表一个通信操作。
输入:

package main

import (
	"fmt"
	"time"
)

func main() {
	inChan := make(chan int, 5)
	strChan := make(chan string, 5)
	go func() {
		time.Sleep(8 * time.Second)
		inChan <- 2
	}()
	go func() {
		time.Sleep(4 * time.Second)
		strChan <- "xx"
	}()
	select {
	case v1 := <-inChan:
		fmt.Println(v1)
	case v2 := <-strChan:
		fmt.Println(v2)
	}
}

输出:

xx

18.多协程中某一协程出现问题的处理
输入:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func print() {
	defer wg.Done()
	for i := 0; i < 10; i++ {
		fmt.Println("i ==> ", i)
	}
}
func divide() {
	defer wg.Done()
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("err ==> ", err)
		}
	}()
	var num1 = 10
	var num2 = 0
	fmt.Println(num1 / num2)
}
func main() {
	wg.Add(2)
	go print()
	go divide()
	wg.Wait()
}

输出:

err ==>  runtime error: integer divide by zero
i ==>  0
i ==>  1
i ==>  2
i ==>  3
i ==>  4
i ==>  5
i ==>  6
i ==>  7
i ==>  8
i ==>  9
  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值