清理你的重複文件,GO語言併發初步

上週筆者的博客《爲什麼大廠上在用GO語言-讀透GO語言的切片》立了個flag,要帶大家共同來實戰一下GO語言的項目,通過這些日子的研究對於GO語言筆者已經路轉粉了。

筆者在接觸GO之前長期從事物聯網操作系統的內核及時序數據庫的開發工作,特別推崇開源精神,曾經參與國產開源數據庫Tdengine與TencentOS等開源項目,在CSDN公衆號中發表過《騰訊開源開年紅!TencentOS 內核正式開源》、《騰訊Tiny OS 組合 NB-IoT,值得程序員一試嗎?》、《Iot數據庫風口已至》等文章。

2019年來自中國的項目和人員爲Github社區的貢獻度均排名世界第二,而且來自中國的開源大潮還在不斷延續,據最新的資料顯示目前Github上最新註冊的開發者中有40%以上來自於中國,甚至有外國的開發者吐槽說Github趨勢榜已經被中文項目所霸佔了,可以說開源已經成爲了我國文化輸出的一張名片,讓世界上其它國家開始學習“中國話”。

在十年前業界普遍流傳着一句話叫做“代碼正在吞沒世界”,後來又說“互聯網世界的一切源自開源”,而直到最近人們才真正醒悟原來雲原生纔是背後的那個大BOSS,而GO語言恰恰是開源+雲原生的基石。凡是不使用雲的都將落後,都無法做到敏捷,跟不上時代。

 

雖然我國在很多基礎軟件的研發領域取得了不少的成果,比如操作系統中的TencentOS系列、Ali Things OS、Rtthread、鴻蒙OS等等,在芯片方面阿里也有無劍100-MCU開源芯片平臺發佈,但是在編程語言方面我們還始終沒有什麼值得一提的進展,因此筆者開始關注到了GO語言。在閱讀了GO語言的代碼之後,可以肯定的講在設計思想上GO語言有很多值得我國學習之處。

Go語言(Github地址:https://github.com/golang/go)是在2007年9月由Rob ert Gries emer, Rob Pike和Ken Thomps共同在谷歌大會上構想出來的,據說時任Google首席軟件工程師的Rob Pike實在無法忍耐C++緩慢的編譯速度,因此他和Robert Griesemer探討了程序設計語言的問題,他們認爲,編程語言的簡約化比增加新特性更加重要。隨後說服了C語言之父Ken Thompson,並共同發起了Golang項目,做爲新型語言的實驗項目。

GO語言可以說是和容器相生相伴的,大名鼎鼎的Docker,完全用GO實現,業界火爆的容器管理系統kubernetes(k8s),完全用GO實現,最新的Docker Swarm,完全用GO實現。而GO語言做爲容器的支柱,使雲計算變得越來越標準化,基於GO語言的容器通過其在併發、性能等方面的特性使得開發者只需關注自己的業務邏輯,而無需顯示地保有計算資源,免去資源管理、系統運維等工作。

如何使用GO語言清理你PC機中的文件

其實這個題目並不難,具體代碼及註釋如下:

package main

import ( //
	"fmt" // fmt 包使用函數實現 I/O 格式化(類似於 C 的 printf 和 scanf 的函數), 格式化參數源自C,但更簡單
	"io/ioutil"
	//"sync"
	//"time"
)

func PrintRepreatFile(path string, fileNameSizeMap map[string]int64, exFileList []string) {

	fs, _ := ioutil.ReadDir(path)
	for _, file := range fs {
		if file.IsDir() {
			
			PrintRepreatFile(path+"/"+file.Name(), fileNameSizeMap, exFileList)//遍歷整個文件系統,如果是目錄則遞歸調用
		
		} else {

			if file.Size() > 1000000 {//設定文件清理閾值,如果大於一定大小再進行清理
				fileSize := fileNameSizeMap[file.Name()]//通過查哈希表的方式來確定,有無重名且大小相同的文件。

				if fileSize == file.Size() {
					fmt.Println(path + "/" + file.Name())//如果有則打印出來

					exFileList = append(exFileList, path+file.Name())//將結果記入切片當中
				} else {

					fileNameSizeMap[file.Name()] = file.Size()
				}
			}

		}

	}

}

func main() {
	//方式一
	fileNameSizeMap := make(map[string]int64, 10000)
	exFileList := make([]string, 100, 1000)
	PrintRepreatFile("E:/test", fileNameSizeMap, exFileList)

}

這個程序在GO語言的環境下可以直接運行使用,其中有幾個知識點,也是咱們前文提到過的,首先是切片的大小一定要設定的相對合適一些,如果容量不夠大造成頻繁擴容非常浪費資源。二是哈希表也就是map沒有併發安全的屬於,在我們這個未引入併發的程序中可以使用,如果有併發操作,那麼map不再適用了。

引子GO語言中的併發

可能很多人和筆者一樣,也是被GO語言的在併發性能所吸引入坑的,GO語言之父也就是UNIX之父Ken Thompson明顯給出了很多建議,根據筆者在操作系統方面的相關經驗來看,GO語言設計中經常參考UNIX內核的設計思路。比如硬定時器的數量有限,無法滿足系統實際運行需要,所以在內核代碼中就會看到基於硬件定時器的軟件定時器的方案,而軟件定時器的數量可以比硬件定時器多幾百倍。

這樣的理念明顯融合到了 goroutine之中,由於其它編程語言往往直接通過系統級別的線程來實現併發功能,但是這樣的方式往往會是大馬拉小車,造成系統資源的浪費。因此GO語言封裝了所有的系統操作,實現了更加輕量級的協程-goroutine。只要使用關鍵字(go)就可以啓動協程,對比C++、JAVA的多線程併發模型,GO的協程更簡單明瞭。

當然協程之間的消息通信與併發控制也是非常重要的一環。在GO語言借鑑了Message Queue的消息隊列機制替代共享內存的方式進行協程間通信,其中管道channel作爲基本的數據類型,保證併發時的操作安全。而且管道的引入還帶來很多實踐中非常實用的功能,比如可以方便實現生產者、消費者等併發設計模式,而這些設計模式在其它使用共享存內存的併發模型中實現起相關功能來非常的繁鎖。

在GO語言中在調用函數前加入go 關鍵字,就能啓動一個協程,也就是一個併發,但是我們上面的程序如果把調用方式改爲:

go PrintRepreatFile("E:/test", fileNameSizeMap, exFileList)

你會發現程序會直接退出,什麼都沒做,所以GO語言的併發對於初學者來說還是有一定門檻的,比如上例中如果想設計成一個並行的程序,如何讓多個協程共同來幫忙找出重複的文件其實還是要費一番周折的。筆者接下來的幾次博客,計劃以這個找到重複文件爲題,帶大家共同來走進GO語言併發的世界。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章