[翻译]理解 GO 语言的内存使用

许多人在刚开始接触 Go 语言时,经常会有的疑惑就是“为什么一个 Hello world 会占用如此之多的内存?”。Understanding Go Lang Memory Usage 很好的解释了这个问题。不过“简介”就是“简介”,更加深入的内容恐怕要读者自己去探索了。另外,文章写到最后,作者飘了,估计引起了一些公愤,于是又自己给自己补刀,左一刀,右一刀……

————翻译分隔线————

理解 Go 语言的内存使用

2014年12月22日,星期一

温馨提示:这仅是关于 Go 语言内存的简介,俗话说不入虎穴、焉得虎子,读者可以进行更加深入的探索。

大多数 Go 开发者都会尝试像这样简单的 hello world 程序:

package main

import (
"fmt"
"time"
)

func main() {
fmt.Println("hi")

time.Sleep(30 * time.Second)
}

然后他们就完全崩溃了。

high_mem-300x38

这个笔记本也只有 16 G 内存!

虚拟内存 vs 常驻内存

Go 管理内存的方式可能与你以前使用的方式不太一样。它会在一开始就保留一大块 VIRT,而 RSS 与实际内存用量接近。

RSS 和 VIRT 之间有什么区别呢?

VIRT 或者虚拟地址空间大小是程序映射并可以访问的内存数量。

RSS 或者常驻大小是实际使用的内存数量。 Continue reading

Profiling Go Programs

转自:http://blog.golang.org/profiling-go-programs (需翻墙)

The Go Blog

Profiling Go Programs

24 June 2011

At Scala Days 2011, Robert Hundt presented a paper titled Loop Recognition in C++/Java/Go/Scala. The paper implemented a specific loop finding algorithm, such as you might use in a flow analysis pass of a compiler, in C++, Go, Java, Scala, and then used those programs to draw conclusions about typical performance concerns in these languages. The Go program presented in that paper runs quite slowly, making it an excellent opportunity to demonstrate how to use Go's profiling tools to take a slow program and make it faster.

By using Go's profiling tools to identify and correct specific bottlenecks, we can make the Go loop finding program run an order of magnitude faster and use 6x less memory.(Update: Due to recent optimizations of libstdc++ in gcc, the memory reduction is now 3.7x.) Continue reading

golang中并发实例

package main

import (
	"fmt"
	//"runtime"
	"os"
	"runtime/pprof" // 引用pprof package
	"time"
)

func main() {
	f, _ := os.Create("profile_file")
	pprof.StartCPUProfile(f)     // 开始cpu profile,结果写到文件f中
	defer pprof.StopCPUProfile() // 结束profile

	startTime := time.Now().Second()
	//runtime.GOMAXPROCS(runtime.NumCPU())

	ch := make(chan int, 100)
	quit := make(chan bool)

	go read(ch, quit)

	for i := 0; i < 2000; i++ {
		ch <- i
		fmt.Println(i)
	}

	quit <- true

	fmt.Println("\r\n====MAIN END====\r\n")
	endTime := time.Now().Second()

	fmt.Println(startTime)
	fmt.Println(endTime)
	fmt.Println("用时:", endTime-startTime, "秒")
}

func read(ch chan int, quit chan bool) {
	for {
		select {
		case value := <-ch:
			fmt.Print("----", value, "----")
		case <-quit:
			break
		}

	}
}

 

在Golang中使用json

由于要开发一个小型的web应用,而web应用大部分都会使用json作为数据传输的格式,所以有了这篇文章。

包引用

import (
    "encoding/json"
    "github.com/bitly/go-simplejson" // for json get
)

用于存放数据的结构体

type MyData struct {
    Name   string    `json:"item"`
    Other  float32   `json:"amount"`
}

这里需要注意的就是后面单引号中的内容。

`json:"item"`

这个的作用,就是Name字段在从结构体实例编码到JSON数据格式的时候,使用item作为名字。算是一种重命名的方式吧。 Continue reading

golang的json操作

package main
 
import (
    "encoding/json"
    "fmt"
    "os"
)
 
type ConfigStruct struct {
    Host              string   `json:"host"`
    Port              int      `json:"port"`
    AnalyticsFile     string   `json:"analytics_file"`
    StaticFileVersion int      `json:"static_file_version"`
    StaticDir         string   `json:"static_dir"`
    TemplatesDir      string   `json:"templates_dir"`
    SerTcpSocketHost  string   `json:"serTcpSocketHost"`
    SerTcpSocketPort  int      `json:"serTcpSocketPort"`
    Fruits            []string `json:"fruits"`
}
 
type Other struct {
    SerTcpSocketHost string   `json:"serTcpSocketHost"`
    SerTcpSocketPort int      `json:"serTcpSocketPort"`
    Fruits           []string `json:"fruits"`
}
 
func main() { 
    jsonStr := `{"host": "http://localhost:9090","port": 9090,"analytics_file": "","static_file_version": 1,"static_dir": "E:/Project/goTest/src/","templates_dir": "E:/Project/goTest/src/templates/","serTcpSocketHost": ":12340","serTcpSocketPort": 12340,"fruits": ["apple", "peach"]}`
 
    //json str 转map
    var dat map[string]interface{}
    if err := json.Unmarshal([]byte(jsonStr), &dat); err == nil {
        fmt.Println("==============json str 转map=======================")
        fmt.Println(dat)
        fmt.Println(dat["host"])
    }
 
    //json str 转struct
    var config ConfigStruct
    if err := json.Unmarshal([]byte(jsonStr), &config); err == nil {
        fmt.Println("================json str 转struct==")
        fmt.Println(config)
        fmt.Println(config.Host)
    }
 
    //json str 转struct(部份字段)
    var part Other
    if err := json.Unmarshal([]byte(jsonStr), &part); err == nil {
        fmt.Println("================json str 转struct==")
        fmt.Println(part)
        fmt.Println(part.SerTcpSocketPort)
    }
 
    //struct 到json str
    if b, err := json.Marshal(config); err == nil {
        fmt.Println("================struct 到json str==")
        fmt.Println(string(b))
    }
 
    //map 到json str
    fmt.Println("================map 到json str=====================")
    enc := json.NewEncoder(os.Stdout)
    enc.Encode(dat)
 
    //array 到 json str
    arr := []string{"hello", "apple", "python", "golang", "base", "peach", "pear"}
    lang, err := json.Marshal(arr)
    if err == nil {
        fmt.Println("================array 到 json str==")
        fmt.Println(string(lang))
    }
 
    //json 到 []string
    var wo []string
    if err := json.Unmarshal(lang, &wo); err == nil {
        fmt.Println("================json 到 []string==")
        fmt.Println(wo)
    }
}

参考第三方json库 simplejson 的用法:http://blog.haohtml.com/archives/16851

转自:http://www.cnblogs.com/go-ios/p/3906251.html

golang中的md5的用法

代码

package main

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
)

func main() {
	// md5 加密的第一种方法
	srcData := []byte("iyannik0215")
	cipherText1 := md5.Sum(srcData)
	fmt.Printf("md5 encrypto is \"iyannik0215\": %x \n", cipherText1)

	// md5 加密的第二种方法
	hash := md5.New()
	hash.Write(srcData)
	cipherText2 := hash.Sum(nil)
	hexText := make([]byte, 32)
	hex.Encode(hexText, cipherText2)
	fmt.Println("md5 encrypto is \"iyannik0215\":", string(hexText))
}
# 执行结果
md5 encrypto is "iyannik0215": b6b20c73e6bc53bc691a6bb559cf9ca9
md5 encrypto is "iyannik0215": b6b20c73e6bc53bc691a6bb559cf9ca9

不同

解释一下两种加密方式的不一样之处.
第一种加密方法:
第一种加密方法所调用的函数

//Source file src/crypto/md5/md5.go
19	// The size of an MD5 checksum in bytes.
20	const Size = 16

130	// Sum returns the MD5 checksum of the data.
131	func Sum(data []byte) [Size]byte {
132		var d digest
133		d.Reset()
134		d.Write(data)
135		return d.checkSum()
136	}

func Sum(data []byte) [Size]byte
其 [Size]byte 是固定死的.所以说第一种方法返回的是 16长度的数组(无法转string类型,需使用第二种加密方法)
第二种加密方法:

//Source file src/crypto/md5/md5.go
50	// New returns a new hash.Hash computing the MD5 checksum.
51	func New() hash.Hash {
52		d := new(digest)
53		d.Reset()
54		return d
55	}
// 这里只放了函数签名部分, 关于函数具体内容这里就不详细复制了.
51	func New() hash.Hash {}
61	func (d *digest) Write(p []byte) (nn int, err error) {}
90	func (d0 *digest) Sum(in []byte) []byte {}

这里使用 func New() hash.Hash {} 函数进行生成对象.
使用 func (d *digest) Write(p []byte) (nn int, err error) {} 方法进行写入要加密的数据.
使用 func (d0 *digest) Sum(in []byte) []byte {} 方法进行数据的加密 看其返回值.
[]byte 可见使用第二种方式加密返回的是 []byte 类型的切片.

转:http://openskill.cn/article/206?utm_source=tuicool&utm_medium=referral

golang中chan实例

package main

import "fmt"

func main() {
 data := make(chan int) // 数据交换队列
 exit := make(chan bool) // 退出通知

go func() {
 for d := range data { // 从队列迭代接收数据,直到 close 。
   fmt.Println(d)
 }

 fmt.Println("recv over.")
 exit <- true // 发出退出通知。
}()

data <- 1 // 发送数据。
data <- 2
data <- 3

close(data) // 关闭队列。

fmt.Println("send over.")

<-exit // 等待退出通知。
}

输出结果:

1
2
3
send over.
recv over.

而如果将上面与 exit chan有关的三行删除掉,则结果为:

1
2
3
send over.

缺少了“recv over."一行,为什么?

大家可以  time.Sleep(time.Second * 2) 来自己分析一下

golang中chan的理解与使用教程

对于 chan 介绍见:https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.7.md

这里我们主要通过实例来介绍对chan的理解及用法.

无Buffer的Channels

实例1:

func main() {
ci := make(chan int)

ci < - 4

value := <-ci
fmt.Println(value)
}

执行结果错误为:

fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:

从上面“fatal error: all goroutines are asleep - deadlock!” 这句我们可以看出是groutings 阻塞了,这里为写阻塞,从“goroutine 1 [chan send]”可以看出来。 Continue reading

golang中flag包的用法

golang中flag包主要用来CLI下,获取命令参数,示例如下mysql.go:

package main

import (
"flag"
"fmt"
)

func main() {
host := flag.String("h", "localhost", "请指定一个主机")
user := flag.String("u", "root", "请指定数据库用户")
port := flag.Int("P", 3306, "Port number to use for commection or 0 for default to, in port 3306")

//var name string
//flag.StringVar(&name, "u", "root", "请指定用户名") 

flag.Parse() //参数解析

fmt.Println("主机地址:", *host)
fmt.Println("用户名:", *user)
fmt.Println("端口:", *port)
}

像flag.Int、flag.Bool、flag.String这样的函数格式都是一样的,第一个参数表示参数名称,第二个参数表示默认值,第三个参数表示使用说明和描述。flag.StringVar这样的函数第一个参数换成了变量地址,后面的参数和flag.String是一样的。

使用flag来操作命令行参数,支持的格式如下:

-id=1 go run mysql.go -h="127.0.0.1" -u="sxf" -P=3307 
--id=1: go run mysql.go --h="127.0.0.1" --u="sxf" --P=3307 
-id 1:  go run mysql.go -h "127.0.0.1" -u "sxf" 
--id 1:  go run mysql.go --h "127.0.0.1" --u "sxf" --P 3307

还是非常方便的。

这里不指定参数的情况,会使用默认值:

go run mysql.go