robintsai / tearupgo Goto Github PK
View Code? Open in Web Editor NEWRead and tear up source code of go
Read and tear up source code of go
Lock
函数,此时没有协程可以再得到这个锁读的权限,直到这个读操作被释放。即阻塞的 Lock
调用,阻塞了其他读操作获取该锁。这种特性禁止了递归读锁。Lock()
会阻塞其他读写请求直到锁被释放。RLock
与 RUnlock
对应,Lock
与 Unlock
对应RLock
。 Lock
就 不能 (不能编译通过)被递归使用。RLock/Lock
就进行 RUnlock/Unlock
,则会报一个运行时错误。RLock/Lock
,而另一个线程中释放锁 RUnlock/Unlock
。Mutex
结构上只有两个方法,Lock
和 Unlock
。同时,将实现这两个方法定义为一个接口 Locker
。
Mutex
结构有两个属性,state
表示当前状态, sema
表示信号(semaphore)。
type Mutex struct {
state int32
sema uint32
}
state
用一个 int32 类型,存储了两部分内容。一部分是状态,位于二进制的后三位,存了四个状态;另一部分是等待队列,其他位。
state 中标记状态的四个值分别为:
mutexLocked
表示被锁定状态,用十进制数 1 表示(... 001);mutexWoken
表示被唤醒状态,用十进制数 2 表示(... 010);mutexStarving
表示饥饿状态,用十进制数 4 表示(... 100)。首先,判断当前是否空闲,若是,则直接设置为上锁状态,并退出。执行 atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked)
方法,此方法比较 m.state
的值和 0
,如果相同,就交换两个值,即设置 m.state
为 1
。
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
return
}
这里省略了内部的
race.Enable
部分,这是用来竞争检测的。详细可以参考internal/race
包文档介绍,在 build 或 run 时,加上-race
参数(go run -race xxx.go
)可以启用竞争检测。
若非空闲状态,则初始化一些变量,进入以下 for 循环。for 循环中:
runtime_Semrelease(&m.sema, true)
(移交给下一个等待者)。runtime_Semrelease(&m.sema, false)
)。muexLocked = 1 << iota
在下一行中会延用公式,即下一行变为 1 << 1
iota
时不再延用公式iota
变成了 0针对于包: workpool/workpool.go
设计上的思考:
pool.elasticJobBuf.Out
通道来判断时机,但其实这样打破了任务执行的顺序性,比如在有些要求时序的场景上就会出现问题(如打日志可能会造成后发生的日志先打印),但一律进行排队的话就不好判断 spawnOneWorker 的时机了。想法:可以通过获取 worker 个数结合 idle 状态个数来设计一下这个问题的解决方案。其他细节:
AddTask(work IWorkload)
函数中目前有两个 if 分支 if p.GetWaitCount() == 0 { 直接 spawn } else { 进行抢占 Out 判断是否 spawn}
,其实还应该加一个,在 p.GetWaitCount() == p.workerCount
时只去从 In 进入队列,不需要再判断新开一个 worker 了。Go 在加载时先执行 init 函数(所以要想读 main()
,要先读懂它),Go 入口文件中有两个 init 函数,一个在文件前面部分,另一个在文件末尾。
init 函数注册了许多 base.Command
到 base.Go.Commands
变量中,可以看到 base.Command
是 go 所有命令的一个结构体。(参考src/cmd/go/internal/base/base.go
文件)
base.Go.Commands = []*base.Command{
bug.CmdBug,
// ...
}
base.Command
中定义了 command 的 Run, UsageLine, Long 等等,其还有一个关键 Commands []*Command
,即它可以链式挂很多命令。
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string)
// UsageLine is the one-line usage message.
// The words between "go" and the first flag or argument in the line are taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short string
// Long is the long message shown in the 'go help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
// Note that subcommands are in general best avoided.
Commands []*Command
}
可以看到 Go 也是一个 Command
类型,上面的命令都挂在了它上
var Go = &Command{
UsageLine: "go",
Long: `Go is a tool for managing Go source code.`,
// Commands initialized in package main
}
第一次知道,init()
还可以定义两个,下面这个 init()
函数会在第一个 init()
函数之后执行,它只是注册了一下命令的 Usage
,下面来读 main()
函数。
src/cmd/go/main.go
首先,有一行 _ = go11tag
,发现是此字段是一个 bool 的 true
。( // +build go1.1
的作用)
flag.Usage = base.Usage
中这个 base.Usage
是这样定义的 var Usage func()
然后解析输入的参数,判断输入的命令,如果是 help
会输出对应的文档信息。
会检查当前环境的配置是否正确。并且从配置文件中读配置信息。
当检查到可执行的命令时,执行 cmd.Run(cmd, args)
,最后退出。
envcmd.MkEnv()
。cmd.Run(cmd, args)
是关键。atExitFuncs
)通过 cfg
了解到 go env
中 GOENV
指向了一个文件 ~/.config/go/env
它中定义了一些环境变量(非默认的会加在这里)
//go:generate .mkalldocs.sh
的用法(注释与 go 之间不可以有空格)
// +build go1.1
的用法
函数当做变量去赋值
var Usage func()
flagUsage = func() {}
flagUsage = Usage
main.go
中有两个 init()
,是依顺序执行的
向 stderr 中写数据,用了这样的方式
w := os.Stderr
bw := bufio.NewWriter(w)
bw.Write([]byte("abc"))
bw.Flush()
os.Getwd()
获取当前目录
filepath.Join(dir, "go.mod")
以文件连接符拼接路径
fileinfo := os.Stat()
查看文件状态,返回一个对象,常用的有 fileinfo.Name()
、fileinfo.IsDir()
和 fileinfo.Mode()
(“drwxrwxr-x”)
os.TempDir()
返回 os 的临时目录
filepath.EvalSymlinks(path string) (string, error)
如果 path
是一个软链,则返回的链接文件的真实目录
filepath.IsAbs(path string) bool
判断是否为绝对路径,它里面就是返回了一个 strings.HasPrefix(path, "/")
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.