Golang学习笔记:goroutine

gorutine的定义:
1.任何函数只需要加上go就能送给调度器运行
2.调度器在合适的点进行切换(可能切换的点:I/O,select,channel,等待锁,函数调用(有时),runtime.Gosched()
3.只是参考,不能保证切换,不能保证在其他地方不切换

 

下面通过代码来详细讲解一下goroutine的用法:

package main

import (
	"fmt"
	"time"
)

func main() {
	for i := 0; i < 10; i++ {
		go func(i int) {
			for {
				     fmt.Printf("Hello from"+ 
					"goroutine %d\n", i)  
			}

		}(i)
	}
	time.Sleep(time.Millisecond)   //如果没有加此行代码,由于main函数与go func是并发执行的,go func还没来得急打印main函数就已经退出了,所以goroutine就被杀死了,所以没有输出结果。
	//fmt.Println(a)
}

 

上述代码如果没有加go,就表示不是并发执行,而且因为该函数没有退出条件,会一直打印Hello form gorutine 0,加了go之后就表示创建了10个协程并发进行运行。

输出结果:

Golang学习笔记:goroutine

如果上述代码中10改为1000,那么就不是所有结果都会在Millsecond之内输出了。

 

goroutine其实 是一种协程coroutine.或者说是与协程比较相像的。

协程Coroutine
1.轻量级“线程”(例如我们在前面可以开1000个线程)
2.非抢占式多任务处理,有协程主动交出控制权,线程我们都知道它任何时候都有可能被操作系统所切换,是抢占的,但协程不一样,是非抢占式的。
3.编译器、解释器、虚拟机层面的多任务
4.多个协程可能在一个或者多个线程上运行(由调度器决定)

Golang学习笔记:goroutine

 

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	var a [10]int
	for i := 0; i < 10; i++ {
		go func(i int) {
			for {
				a[i]++ 
				 runtime.Gosched() 
			}

		}(i)
	}
	time.Sleep(time.Millisecond) //如果没有加此行代码,由于main函数与go func是并发执行的,go func还没来得急打印main函数就已经退出了,所以goroutine就被杀死了,所以没有输出结果。
	fmt.Println(a)
}

上述代码runtime.Gosched()手动交出控制权,会让别人也能运行,因为上述代码go func是一个协程,因为该代码为死循环,所以没有办法交出控制权,会死循环挂掉。而之前因为printf涉及i,o操作,会有协程之间的切换,所以能输出的结果,但是因为a【i】++没有涉及协程之间的切换,所以会挂掉,所以可以加上runtime.Gosched()手动交出控制权。

输出结果:Golang学习笔记:goroutine

 

小结:

Golang学习笔记:goroutine

main函数可以开出很多协程,让这些协程并发执行,而且这些协程也有可能映射到一个线程上运行。