前言:很久没写手记,不是不想写,而是不知道写什么。虽然这段时间进步很快,也学到了很多东西,但是一下笔就发现将要分享的内容没有什么新意,完全是炒冷饭,也就放弃了。不过太久没写,总觉得生活中缺少了一些东西,会有种学了一堆没用知识的错觉,因此偶尔分享下,也算对自己学习的鞭策。
今天分享的内容是go语言并发操作文件的代码。经过这段时间的学习,个人觉得go语言优雅轻量,有很多思想和设计是javascript中所欠缺的。底层设计特别是并发机制基本上是javascript完全缺乏的,因此本篇分享这个内容,以下是正文:
package main
import (
"fmt"
"runtime"
"path"
"os"
"bufio"
"strings"
"sync"
)
//将文件相对路径转化为绝对路径
func getFileAbsPath3(relativePath ... string) []string {
var ret = []string{}
_, file, _, _ := runtime.Caller(1)
for _, dir := range relativePath {
var filePath = path.Join(path.Dir(file), dir)
ret = append(ret, filePath)
}
return ret
}
func filterRepeat3() {
var absPaths = getFileAbsPath3("./2.txt", "./3.txt", "./4.txt")
//设置一个并发控制wgp
wgp := sync.WaitGroup{}
//设置一个存储map
var valuesMap map[string]int = map[string]int{}
for _, dir := range absPaths {
wgp.Add(1)
//并发打开多个文件并读取文件内容
go func(filePath string) {
fmt.Println("并发打开文件的顺序为: ", filePath)
file, error := os.Open(filePath)
//此处一定要记住close,否则可能会导致文件描述符用完
defer file.Close()
if (error != nil) {
fmt.Println("error: ", error)
}
//此处建议使用scanner,如果使用NewReader还需要处理空行和只有一行的情况,不推荐
scanner := bufio.NewScanner(file)
//逐行扫描,知道直接或出错
for scanner.Scan() {
str := scanner.Text()
str = strings.TrimSpace(str)
valuesMap[str] += 1
}
wgp.Add(-1)
}(dir)
}
//等待并发程序全部结束
wgp.Wait()
for key, value := range valuesMap {
if value > 1 {
fmt.Println("找到重复行,重复的行值为:", key, "重复次数为:", value)
}
}
fmt.Println(valuesMap)
}
func main() {
filterRepeat3()
}这个版本看上去很清晰,代码也比较简单,但是这是一个有问题的代码,问题就出在go语言是并发变成的语言,可能会报错go fatal error: concurrent map writes(同时写或者读的时候在写)。如何处理呢?两种方式,一种是采用go语言锁,sync.mutex。一种是采用通道,串行写入。这里我采用锁的方式,将读和写都锁定,这样就避免了并发导致的读写冲突问题,代码如下:
package main
import (
"bufio"
"fmt"
"os"
"path"
"runtime"
"strings"
"sync"
)
//将文件相对路径转化为绝对路径
func getFileAbsPath3(relativePath ...string) []string {
var ret = []string{}
_, file, _, _ := runtime.Caller(1)
for _, dir := range relativePath {
var filePath = path.Join(path.Dir(file), dir)
ret = append(ret, filePath)
}
return ret
}
var valuesMap = map[string]int{}
var mutex sync.Mutex
//加上读写锁,否则会出现同时读写的冲突
func write(k string) {
mutex.Lock()
defer mutex.Unlock()
valuesMap[k] += 1
}
func filterRepeat3() {
var absPaths = getFileAbsPath3("./2.txt", "./3.txt", "./4.txt")
//设置一个并发控制wgp
wgp := sync.WaitGroup{}
//设置一个存储map
for _, dir := range absPaths {
wgp.Add(1)
//并发打开多个文件并读取文件内容
go func(filePath string) {
fmt.Println("并发打开文件的顺序为: ", filePath)
file, error := os.Open(filePath)
//此处一定要记住close,否则可能会导致文件描述符用完
defer file.Close()
if error != nil {
fmt.Println("error: ", error)
}
//此处建议使用scanner,如果使用NewReader还需要处理空行和只有一行的情况,不推荐
scanner := bufio.NewScanner(file)
//逐行扫描,知道直接或出错
for scanner.Scan() {
str := scanner.Text()
str = strings.TrimSpace(str)
write(str)
}
wgp.Add(-1)
}(dir)
}
//等待并发程序全部结束
wgp.Wait()
for key, value := range valuesMap {
if value > 1 {
fmt.Println("找到重复行,重复的行值为:", key, "重复次数为:", value)
}
}
fmt.Println(valuesMap)
}
func main() {
for i := 0; i < 5000; i++ {
filterRepeat3()
}
}代码并不复杂,有些稍微需要描述的地方都有代码注释。另外最后推荐两本go语言书籍,特别值得一看:《go并发编程实战第二版》《go程序设计语言》
thx~
點擊查看更多內容
1人點贊
評論
評論
共同學習,寫下你的評論
評論加載中...
作者其他優質文章
正在加載中
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦