Go语言初尝
对于语言设计之争, 唯一需要牢记的一句话是: 如果把 C 变成 C++, 那么 C 就消失了。
Go 是一个轻量级的简洁的支持并发的现代语言, 可以用于探索性个人项目, 这是我想学这门语言的主要原因。 对于有一定编程经验的人来说, 学习一种新语言的方式是, 先概览下语言特性, 然后编写一个中等规模的程序, 尽可能地运用到大部分重要特性。
Go 的主要语言特性:
l 1. 静态类型 + 类型推导;
下面的程序用于计算一个目录下所有文件或目录的大小。
$ go build -o dirsize dirsize_module.go time2.go
$ dirsize
dirsize_module.go
package main import ( "fmt" // "log" "os" "sort" "time" ) import "C" type ShortFileInfo struct { fileName string size int64 } type FileInfoSlice []ShortFileInfo func (fileInfo *ShortFileInfo) Desc() string { return fmt.Sprintf("{%s:%s}", fileInfo.fileName, readableSize(fileInfo.size)) } func (fileInfos FileInfoSlice) Len() int { return len(fileInfos) } func (fileInfos FileInfoSlice) Swap(i, j int) { fileInfos[i], fileInfos[j] = fileInfos[j], fileInfos[i] } func (fileInfos FileInfoSlice) Less(i, j int) bool { return fileInfos[i].size > fileInfos[j].size } type IOError struct { msg string err error } func (ioe IOError) Error() string { return "Error: " + ioe.msg + "\nCause: " + ioe.err.Error() } func produceFiles(dirName string) (fileInfos []os.FileInfo, e error) { path, err := os.Open(dirName) if err != nil { //log.Fatal(err) return nil , IOError{"failed to open " + dirName, err} } defer path.Close() fileInfos, readerr := path.Readdir(0) if readerr != nil { //log.Fatal(readerr) return nil, IOError{"failed to read " + dirName, readerr} } return fileInfos, nil } func procFile(fileInfo os.FileInfo, baseDirName string, channelBuffer chan ShortFileInfo) { var filesize int64 fileName := fileInfo.Name() if fileInfo.IsDir() { filesize = totalFilesizeInDir(fileInfo, baseDirName) } else { filesize = fileInfo.Size() } shortFileInfo := ShortFileInfo{fileName, filesize} fmt.Println(time.Now().String() + " store: " + shortFileInfo.Desc()) channelBuffer <- shortFileInfo } func totalFilesizeInDir(fileInfo os.FileInfo, baseDirName string) int64 { var filesize int64 = 0 fileInfos, _ := produceFiles(baseDirName + "/" + fileInfo.Name()) for _, subfileInfo := range fileInfos { if subfileInfo.IsDir() { filesize += totalFilesizeInDir(subfileInfo, baseDirName+"/"+fileInfo.Name()) } else { filesize += subfileInfo.Size() } } return filesize } func sleep(ns int) { time.Sleep(time.Duration(time.Second) * time.Duration(ns)) } const ( B int64 = 1 KB int64 = 1024 MB int64 = 1024 * 1024 GB int64 = 1024 * 1024 * 1024 TB int64 = 1024 * 1024 * 1024 * 1024 ) const formatF string = "%8.4f" func readableSize(sizeInBytes int64) string { switch { case B <= sizeInBytes && sizeInBytes < KB: return fmt.Sprintf("%dB", sizeInBytes) case KB <= sizeInBytes && sizeInBytes < MB: return fmt.Sprintf(formatF+"KB", float64(sizeInBytes)/float64(KB)) case MB <= sizeInBytes && sizeInBytes < GB: return fmt.Sprintf(formatF+"MB", float64(sizeInBytes)/float64(MB)) case GB <= sizeInBytes && sizeInBytes < TB: return fmt.Sprintf(formatF+"GB", float64(sizeInBytes)/float64(GB)) case TB <= sizeInBytes: return fmt.Sprintf(formatF+"TB", float64(sizeInBytes)/float64(TB)) default: return "0" } } //export mainProc func mainProc() { start_1 := time.Now().Unix() baseDirName := "/home/lovesqcc" //baseDirName := "/notExist" //baseDirName := "/" fileList, err := produceFiles(baseDirName) if err != nil { fmt.Println(err.Error()) os.Exit(1) } fileNumber := len(fileList) channelBuffer := make(chan ShortFileInfo, fileNumber) fileInfoMap := make(map[string]int64, fileNumber) for _, fileInfo := range fileList { go procFile(fileInfo, baseDirName, channelBuffer) } var fileInfos = make([]ShortFileInfo, fileNumber+1) timeout := make(chan int, 1) go func() { secs := 3 sleep(secs) timeout <- secs }() for count := 0; count <= fileNumber; { select { case fileInfo := <-channelBuffer: fmt.Println(time.Now().String() + " fetch: " + fileInfo.Desc()) fileInfoMap[fileInfo.fileName] = fileInfo.size fileInfos[count] = fileInfo count++ case secs := <- timeout: fmt.Printf("%d s timout ! Exit Loop\n", secs) os.Exit(1) default: if count == fileNumber { close(channelBuffer) } fmt.Println("Waiting for data ...") } } sort.Sort(FileInfoSlice(fileInfos)) for _, fileInfo := range FileInfoSlice(fileInfos) { fmt.Println("File " + fileInfo.fileName + " : " + readableSize(fileInfo.size)) } var totalSize int64 totalSize = 0 for _, filesize := range fileInfoMap { totalSize += filesize } fmt.Printf("Total size in %s:%dB %s\n", baseDirName, totalSize, readableSize(totalSize)) end_1 := time.Now().Unix() fmt.Printf("start=%d, end=%d\n",start_1, end_1) fmt.Printf("Time cost: %dms\n", (end_1-start_1)*1000) }
time2.go
package main /* #include<stdio.h> #include<time.h> extern int mainProc(); int printTimeCost() { printf("exec printTimeCost"); time_t start = 0, end = 0; long duration = 0; start = time(NULL); mainProc(); end = time(NULL); duration = (end - start) *1000; return duration; } */ import "C" import "fmt" func main() { fmt.Printf("cost: %dms\n", C.int(C.printTimeCost())) }
参考资料:
1. 《Go语言编程》 许式伟著。
2. Go 轻松学: https://github.com/jemygraw/TechDoc
3. Go 实例学习: https://gobyexample.com/
4. Go 并发之美: http://www.cnblogs.com/yuxingfirst/archive/2012/11/28/2792366.html
5. Go 文档: https://go-zh.org/doc/
6. C-Go 互操作 : http://tonybai.com/2012/09/26/interoperability-between-go-and-c/
7. Go 标准库: http://studygolang.com/pkgdoc
8. Why Go is Not Good: http://yager.io/programming/go.html