Go语言初尝


        对于语言设计之争, 唯一需要牢记的一句话是: 如果把 C 变成 C++, 那么 C 就消失了。

        Go 是一个轻量级的简洁的支持并发的现代语言,  可以用于探索性个人项目, 这是我想学这门语言的主要原因。 对于有一定编程经验的人来说, 学习一种新语言的方式是, 先概览下语言特性, 然后编写一个中等规模的程序, 尽可能地运用到大部分重要特性。

 

        Go 的主要语言特性:

         l 1.  静态类型 + 类型推导;

          l 2.  简化的控制结构: if , for , switch;
          l 3.  可命名的多返回值的函数;
          l 4.  内置容器支持: 数组、Slice、Map ;
          l 5.  简化的指针与引用;
          l 6.  简化的对象特性: 结构体与非侵入式接口;
          l 7.  内置的并发支持: go, Goroutine & Channel ;
          l 8.  反射、匿名函数与闭包;
          l 9.  便捷地 CGo 交互;
          l 10. 内置 GC ;
          l 11. 包管理。
 

 

        下面的程序用于计算一个目录下所有文件或目录的大小。  

         $ 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

 

posted @ 2014-07-24 19:58  琴水玉  阅读(401)  评论(0编辑  收藏  举报