golang核心基础编程实战

一 文件操作

1.1 读取文件

package main

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

func main() {
	file, err := os.Open("d:/Marine_Jonas/123.txt")
	if err != nil {
		fmt.Println("打开文件失败!,", err)
	}
	//函数退出时,关闭文件
	defer file.Close()
	//创建一个流
	reader := bufio.NewReader(file)
	//读取操作
	for {
		readString, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		}
		fmt.Println(readString)
	}
	fmt.Println("读取结束")
}

1.2 写入文件

package main

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

func main() {
	file, err := os.OpenFile("d:/Marine_Jonas/123.txt", os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println("打开文件失败", err)
	}
	//即时将文件关闭
	defer file.Close()
	//写入文件操作---》io流---》缓冲输出流(带缓冲区)
	writer := bufio.NewWriter(file)
	for i := 0; i < 10; i++ {
		writer.WriteString("nihao ocean\n")
	}
	//流带缓冲区,刷新数据--》真正写入文件
	//writer.Flush() 函数的作用是将 缓冲区中的数据立即写入文件
	writer.Flush()
}

1.3 复制文件

package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	//源文件
	file1 := "d:/Marine_Jonas/123.txt"
	//目标文件
	file2 := "d:/Marine_Jonas/456.txt"
	//对目标文件进行读取
	file, err := ioutil.ReadFile(file1)
	if err != nil {
		fmt.Println("读取失败")
	}
	//写出文件
	err = ioutil.WriteFile(file2, file, 0666)
	if err != nil {
		fmt.Println("写入失败!")
	}
}

二 协程

2.1 协程

package main

import (
	"fmt"
	"time"
)

func main() {
	//匿名函数+外部变量 = 闭包
	for i := 1; i <= 5; i++ {
		//go func() { //打印会出现6 相当于 i为外部变量 随着i的变化 fmt.Println(i)调用的i不同 调用函数时 值没有给定
		//	fmt.Println(i)
		//}()
		//怎么样才能保证他一定,在调用 fmt.Println(n) 值已经给定
		go func(n int) {
			fmt.Println(n)
		}(i)
	}
	time.Sleep(time.Second * 2)
}

2.2 使用waitgroup控制线程结束

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {
	//为了不使用 time.Sleep(time.Second * 2) 控制主线程结束
	//解决主线程在子协程结束后自动结束
	//可以最开始在知道协程次数的情况下先Add操作 wg.Add(5)
	for i := 1; i <= 5; i++ {
		wg.Add(1) //协程开始的时候操作+1
		//启动五个协程
		go func(n int) {
			defer wg.Done() //协程执行完减1
			fmt.Println(n)
		}(i)
	}
	//主线一直在阻塞,什么时候减为0,就停止了
	wg.Wait()
}

2.3 多协程操作同一数据案例

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup //只定义无需赋值
var totalNum int

func add() {
	defer wg.Done()
	for i := 0; i < 10000; i++ {
		totalNum = totalNum + 1
	}
}
func sub() {
	defer wg.Done()
	for i := 0; i < 10000; i++ {
		totalNum = totalNum - 1
	}
}
func main() {
	wg.Add(2)
	go add()
	go sub()
	wg.Wait()
	fmt.Println(totalNum)
}

//操作结果永不为0 为什么?
//因为 是交替执行的

三、锁

3.1使用互斥锁解决2.3问题

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup //只定义无需赋值
var totalNum int
var lock sync.Mutex

func add() {
	defer wg.Done()
	for i := 0; i < 10000; i++ {
		lock.Lock()
		totalNum = totalNum + 1
		lock.Unlock()
	}
}
func sub() {
	defer wg.Done()
	for i := 0; i < 10000; i++ {
		lock.Lock()
		totalNum = totalNum - 1
		lock.Unlock()
	}
}
func main() {
	wg.Add(2)
	go add()
	go sub()
	wg.Wait()
	fmt.Println(totalNum)
}

//操作结果永不为0 为什么?
//因为 是交替执行的

3.2 读写锁

2】读写锁
RWMutex是一个读写锁,其经常用于读次数远远多于写次数的场景.
---在读的时候,数据之间不产生影响,   写和读之间才会产生影响
package main

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

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 write() {
	defer wg.Done()
	lock.Lock()
	fmt.Println("开始修改数据")
	time.Sleep(time.Second * 10)
	fmt.Println("修改数据成功")
	lock.Unlock()
}
func main() {
	wg.Add(6)
	//启动协程 场合:读多写少
	for i := 0; i < 5; i++ {
		go read()
	}
	go write()
	wg.Wait()
}



四 管道

4.1 关闭管道

package main

import "fmt"

func main() {
	//定义管道
	var intChan chan int
	//通过make初始化:管道可以存放3个int类型的数据
	intChan = make(chan int, 3)
	//在管道存放数据
	intChan <- 10
	intChan <- 20
	//关闭管道:
	close(intChan)
	//再次写入数据:---->报错
	//intChan <- 30
	//当管道关闭后,读取数据是可以的:
	num := <-intChan
	fmt.Println(num)
}

4.2 遍历管道

package main

import "fmt"

func main() {
	intChan := make(chan int, 100)
	for i := 0; i < 100; i++ {
		intChan <- i
	}
	//在遍历前,如果没有关闭管道,就会出现deadlock的错误
	//所以我们在遍历前要进行管道的关闭
	close(intChan)
	//遍历 for range
	for v := range intChan {
		fmt.Println(v)
	}
}

4.3 协程和管道协同工作

package main

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

/*
【1】案例需求:
请完成协程和管道协同工作的案例,具体要求:
1) 开启一个writeData协程,向管道中写入50个整数.
2) 开启一个readData协程,从管道中读取writeData写入的数据。
3) 注意: writeData和readDate操作的是同一个管道
4) 主线程需要等待writeData和readDate协程都完成工作才能退出
*/
var wg sync.WaitGroup

//写
func write(intChan chan int) {
	defer wg.Done()
	for i := 0; i < 50; i++ {
		intChan <- i
		fmt.Println("写入的数据是", i)
		time.Sleep(time.Second)
	}
}

//读
func read(intChan chan int) {
	defer wg.Done()
	for v := range intChan {
		fmt.Println("读入的数据是", v)
		time.Sleep(time.Second)
	}
}
func main() {
	intChan := make(chan int, 50)
	wg.Add(2)
	go write(intChan)
	go read(intChan)
	wg.Wait()
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值