Go学习协程和调度器

协程

go func() {}()

go语言对并发编程有一个原生的支持,这个再通用型语言里面是不常见的.

package main

import "fmt"

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

Go学习协程和调度器_第1张图片
控制台什么都没有打印直接退出了;

  • 匿名函数加上go;就不是说再main里面调用这个函数,而是开一个goroutine并发的执行这个函数
  • 因为我们是并发执行的,main和匿名函数都是并发执行的,程序还来不及打印东西,main就把循环执行完了,然后main就退出了.go语言的程序一旦main退出了,所有的goroutine都会被杀死;那些goroutine来没来得及执行就被干掉了;所以控制台没有打印内容

time.Sleep

package main

import (
	"fmt"
	"time"
)

func main() {
	for i := 0; i < 1000; i++ {
		go func(i int) {
			for{
				fmt.Printf("Hello from goroutine %d
", i)
			}
		}(i)
	}
	time.Sleep(time.Millisecond)
}

Go学习协程和调度器_第2张图片

非抢占式多任务处理

package main

import (
	"fmt"
	"time"
)

func main() {
	var arr [10]int
	for i := 0; i < 10; i++ {
		go func(i int) {
			for {
				arr[i]++
			}
		}(i)
	}
	time.Sleep(time.Millisecond)
	fmt.Println(arr)
}

Go学习协程和调度器_第3张图片
Go学习协程和调度器_第4张图片
**代码再死循环中一直退不出来,是因为goroutine没有机会交出控制权;交不出控制权就只能死循环下去. **

runtime.Gosched

package main

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

func main() {
	var arr [10]int
	for i := 0; i < 10; i++ {
		go func(i int) {
			for {
				arr[i]++
				runtime.Gosched()
			}
		}(i)
	}
	time.Sleep(time.Millisecond)
	fmt.Println(arr)
}

Go学习协程和调度器_第5张图片
**runtime.Gosched()**可以手动的交出控制权

go run -race

package main

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

func main() {
	var arr [10]int
	for i := 0; i < 10; i++ {
		go func() {
			for {
				arr[i]++
				runtime.Gosched()
			}
		}()
	}
	time.Sleep(time.Millisecond)
	fmt.Println(arr)
}

Go学习协程和调度器_第6张图片
如果直接引用循环中的i程序就会报错:
Go学习协程和调度器_第7张图片
Go学习协程和调度器_第8张图片
我们直接引用循环中的i,goroutine函数内的i就是一个闭包,循环中的i和goroutine函数内的i是一个i,再循环结束的时候i已经等于10,goroutine函数再去引用i时,就会报错

package main

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

func main() {
	var arr [10]int
	for i := 0; i < 10; i++ {
		go func(i int) {
			for {
				arr[i]++
				runtime.Gosched()
			}
		}(i)
	}
	time.Sleep(time.Millisecond)
	fmt.Println(arr)
}

Go学习协程和调度器_第9张图片

总结

  • 轻量级"线程"
  • 非抢占式多任务处理,由协程主动交出控制权
  • 编译器/解释器/虚拟机层面的多任务;不是操作系统层面的多任务
  • 多个协程可能再一个或多个线程上运行

其他语言中的协程

  • C++: Boost.Coroutine

  • Java:不支持;Java不是完全不支持,有一些第三方的JVM会在标准的JVM的基础上加一些对协程的支持

  • python

    • 3.5以前使用yield关键字实现协程
    • 3.5加入了async def对协程的原生支持

调度器

概念

Go学习协程和调度器_第10张图片
Go学习协程和调度器_第11张图片

  • 有些协程可能放在一个线程里面,有些协程可能两个放在一个线程里面,有些协程可能多个协程放在一个线程里面;到底怎么存放是由调度器来控制的

    package main

    import (
    “fmt”
    “time”
    )

    func main() {
    for i := 0; i < 1000; i++ {
    go func(i int) {
    for {
    fmt.Printf("Hello from goroutine %d
    ", i)
    }
    }(i)
    }
    time.Sleep(time.Second)
    }

Go学习协程和调度器_第12张图片

Go学习协程和调度器_第13张图片
开了1000个协程,但其实只在12个线程上面运行!

协程的定义

  • 任何函数只需加上go就能送给调度器运行
  • 不需要再定义时区分是否异步函数
  • 调度器再合适点进行切换
  • 使用-race来检测数据访问的冲突

协程可能的切换点

  • I/O,select
  • channel
  • 等待锁
  • 函数调用(有时)
  • runtime.Gosched()
  • 以上几点只是参考,不能保证切换,不能保证再其他的地方不切换

总结

写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于 java开发 的学习思路及方向。从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。

由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的Gitee获取。
还有 高级java全套视频教程 java进阶架构师 视频+资料+代码+面试题!

全方面的java进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。

你可能感兴趣的:(java,后端,golang,学习,c语言)