104 |
--------------------------------------------------------------------------------
/basis/functions.md:
--------------------------------------------------------------------------------
1 | # 函数
2 |
3 | ## 1. 函数定义与调用
4 |
5 | ```go
6 | //1、函数组成:关键字func ,函数名,参数列表,返回值,函数体,返回语句
7 | //先名称后类型
8 | func 函数名(参数列表)(返回值列表){ //参数列表和返回值列表以变量声明的形式,如果单返回值可以直接加类型
9 | 函数体
10 | return //返回语句
11 | }
12 | //例子
13 | func Add(a,b int)(ret int,err error){
14 | //函数体
15 | return //return语句
16 | }
17 |
18 | //2、函数调用
19 | //先导入函数所在的包,直接调用函数
20 | import "mymath"
21 | sum,err:=mymath.Add(1,2) //多返回值和错误处理机制
22 | //可见性,包括函数、类型、变量
23 | //本包内可见(private):小写字母开头
24 | //包外可见(public):大写字母开头
25 | ```
26 |
27 | ## 2. 不定参数
28 |
29 | ```go
30 | //1、不定参数的类型
31 | func myfunc(args ...int){ //...type不定参数的类型,必须是最后一个参数,本质是切片
32 | for _,arg:=range args{
33 | fmt.Println(arg)
34 | }
35 | }
36 | //函数调用,传参可以选择多个,个数不定
37 | myfunc(1,2,3)
38 | myfunc(1,2,3,4,5)
39 |
40 | //2、不定参数的传递,假如有个变参函数myfunc2(args ...int)
41 | func myfunc1(args ...int){
42 | //按原样传递
43 | myfunc2(args...)
44 | //传递切片
45 | myfunc2(args[1:]...)
46 | }
47 |
48 | //3、任意类型的不定参数,使用interface{}作为指定类型
49 | func Printf(format string,args ...interface{}){ //此为标准库中fmt.Printf()函数的原型
50 | //函数体
51 | }
52 | ```
53 |
54 | ## 3. 多返回值
55 |
56 | ```go
57 | //多返回值
58 | func (file *File) Read(b []byte) (n int,err error)
59 | //使用下划线"_"来丢弃返回值
60 | n,_:=f.Read(buf)
61 | ```
62 |
63 | ## 4. 匿名函数
64 |
65 | 匿名函数:不带函数名的函数,可以像变量一样被传递。
66 |
67 | ```go
68 | func(a,b int,z float32) bool{ //没有函数名
69 | return a*b
20 |
21 | # 2. G-P-M调度模型
22 |
23 | **调度模型:**
24 |
25 |
26 |
27 | **G-P-M对应关系:**
28 |
29 |
30 |
31 | ## 2.1. 基本概念
32 |
33 | - M:machine,代表系统内核进程,用来执行G。(工人)
34 | - P:processor,代表调度执行的上下文(context),维护了一个本地的goroutine的队列。(小推车)
35 | - G:goroutine,代表goroutine,即执行的goroutine的数据结构及栈等。(砖头)
36 |
37 | ## 2.2. 基本流程
38 |
39 | 调度的本质是将G尽量均匀合理地安排给M来执行,其中P的作用就是来实现合理安排逻辑。
40 |
41 |
42 |
43 | - P的数量通过 `GOMAXPROCS()` 来设置,一般等于CPU的核数,对于一次代码执行设置好一般不会变。
44 | - P维护了一个本地的G队列(runqueue),包括正在执行和待执行的G,尽量保证所有的P都匹配一个M同时在执行G。
45 | - 当P本地goroutine队列消费完,会从全局的goroutine队列(global runqueue)中拿goroutine到本地队列。P也会定期检查全局的goroutine队列,避免存在全局的goroutine没有被执行而"饿死"的现象。
46 | - P和M是动态形式的一对一的关系,P和G是动态形式的一对多的关系。
47 |
48 | ## 2.3. 抢占式调度(阻塞)
49 |
50 |
51 |
52 | 当goroutine发生阻塞的时候,可以通过P将剩余的G切换给新的M来执行,而不会导致剩余的G无法执行,如果没有M则创建M来匹配P。
53 |
54 | 当阻塞的goroutine返回后,进程会尝试获取一个上下文(Context)来执行这个goroutine。一般是先从其他进程中"偷取"一个Context,如果"偷取"不成功,则将goroutine放入全局的goroutine中。
55 |
56 | ## 2.4. 偷任务
57 |
58 |
59 |
60 | P可以偷任务即goroutine,当某个P的本地G执行完,且全局没有G需要执行的时候,P可以去偷别的P还没有执行完的一半的G来给M执行,提高了G的执行效率。
61 |
62 |
63 |
64 | 参考:
65 |
66 | - http://morsmachine.dk/go-scheduler
67 | - [Scalable Go Scheduler Design Doc](
163 | Beego is a simple & powerful Go web framework which is inspired by tornado and sinatra.
164 |
165 | Official website: {{.Website}}
166 |
167 | Contact me: {{.Email}}
168 |