我们在应用调试或者线上业务中经常会用到日志功能,而 Go 语言内置了 log 模块。
log 模块的使用
先来看下 log 模块的基本使用:
package main
import (
"log"
)
func main() {
log.Println("hello log.Println")
log.Printf("hello %s", "log.Printf")
}
我们运行一下可以看到如下输出:
> $ go run main.go
2018/10/29 10:45:39 hello log.Println
2018/10/29 10:45:39 hel
关于线程
我们每运行的一个程序都会创建一个进程,每个进程都有一个初始线程,而后初始线程可以创建更多线程,每个线程互相独立地运行。线程因为其轻量和易用性在并发编程中被大量的使用。而 goroutine 就是基于线程的。线程的实现模型主要有3种:用户级线程模型、内核级线程模型和两级线程模型(或者叫做混合型线程模型)。他们之间的区别就是用户线程和系统最小调度单元内核调度实体(KSE,Kernal Scheduling Entity)的对应关系不同。
用户级线程模型
用户线程与内核线程KSE是多对一的映射模型,多个用户线程一般都是从属于单个进程,并且用户线程的调度都是用户程序的线程库完成的,不需要操作
临时忽略掉struct中空字段
type User struct {
Email string `json:"email"`
Password string `json:"password"`
}
当我们把用户信息返回给前端的时候显然需要忽略调Password 字段,则可以这样做:
json.Marshal(struct{
*User
Password bool `json:"password,omitempty"`
}{
User:user,
})
临时添加额外字段
type User struct {
Email string `json:"
我们首先编写一个简单的Golang服务
package main
import "net/http"
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8001", nil)
}
func hello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
}
运行服务
$ go run main.go
访问 http://127.0.0.1:8001 页面返回
Hello world!
构建运
Go语言的条件编译是由go/build包支持的,通过条件编译我们可以实现根据不同的参数编译包里不同的文件。
Go是怎么支持条件编译的
Go通过在源代码里添加编译标签(build tag)实现条件编译的。编译标签是以// +build开始,并且出现在代码文件的最开始。构建选项规则如下:
以逗号分割的选项是并的关系
以空格分割的选项是或的关系
条件项的名字用字母+数字表示,!表示否定的意思
构建标签后必须留一行空行
例如如下的例子:
// +build linux,386 darwin,!cgo
对应的布尔表达式就是
(linux AND 386) OR (darwin AND (NOT cg
内存对齐的作用
平台原因(移植):不是所有的硬件平台都可以访问任意位置上的任意数据的,有些硬件只能在特定位置取特定数据。
性能问题:经过内存对齐,CPU的内存访问速度会提升。因为对齐的元素只需要一次内存访问,未对齐的需要两次。
性能问题
一般程序员会认为内存如下图所示,是有一个个的字节组成,而CPU却不是这样看待的。
CPU把内存当作一块一块的,块的大小可以是2、4、8、16字节大小,因此CPU读取内存是一块一块读取的。(块的大小称为内存读取粒度)
假设CPU要读取一个int型4字节大小的数据,分两种情况讨论:
数据从0字节开始
数据从1字节开始
假设内存读取粒度为4
Go并发调度器解析之实现一个协程池
深入golang之---goroutine并发控制与通信
night-reading-go
Go语言·听说你想让程序运行的更快?
年终盘点!2017年超有价值的Golang文章
飞雪无情的博客
鸟窝
Go 命令详解
goroutine 实现原理
让我们执行如下代码:
package main
import "fmt"
func main() {
v := []int{1, 2, 3}
for i := range v {
println(i)
}
fmt.Println(v)
}
我们可能会得到如下结果(但每次都未必一样):
0
1
[1 2 3]
2
为什么呢?
fmt.Println把结果输出到标准错误(standard error)中,println把结果输出到标准输出(standard output),因为两个输出的目标不一样,所以顺序是不固定的。
golang中字符串格式化输出
package main
import (
"fmt"
"os"
)
type point struct {
x, y int
}
func main() {
// Go提供了几种打印格式,用来格式化一般的Go值,例如
// 下面的%v打印了一个point结构体的对象的值
p := point{1, 2}
fmt.Printf("%v\n", p)
// 如果所格式化的值是一个结构体对象,那么`%+v`的格式化输出
// 将包括结构体的成员名称和值
fmt.Printf("%
自增和自减
golang里包含其他语言常用的自增i++ 和自减i--,但是在golang里他们是语句而不是表达式,所以j=i++这种是错误的写法,而且golang也不支持++和--放在变量前面如++i的形式。
i++ // i的值+1
i-- // i的值-1
++i //错误
--i // 错误
j = i-- //错误
短变量声明只能在函数内部不能再外部
s := "" //错误
func main() {
s := ""
prinltln(s)
}
new只是一个预定义的函数,它并不是一个关键字
func delta(old, new int) int { return