关于go的调度问题

jingyugao · 2018-09-13 00:03:48 · 1164 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2018-09-13 00:03:48 的主题,其中的信息可能已经有所发展或是发生改变。

按照go的说明,goroutine的调度方式为先运行最后一个goroutinue,剩下的按照顺序依次运行。 若无系统调用则不发生调度 若无非内敛函数调用,则不发生抢占式调度(go 1.4) 可是以下代码的结果不太明白 // main

func main() {

data := make([]byte, 256)
for i := 0; i < 256; i++ {
    data[i] = byte(i)
}
runtime.GOMAXPROCS(1)
exitChan := make(chan int, 10)
t0 := time.Now().UnixNano()
for i := 0; i < 10; i++ {
    go func(j int) {
        ret := uint64(0)
        for x := uint64(0); x < uint64(j*40000000); x++ {
            ret = uint64(utils.MurmurHash2(data, uint32(ret)))
        }
        exitChan <- j
    }(i)
}
for i := 0; i < 10; i++ {
    fmt.Print(<-exitChan, time.Now().UnixNano()-t0, "\n")
}

} // Mixing constants; generated offline. const ( M = 0x5bd1e995 BIGM = 0xc6a4a7935bd1e995 R = 24 BIGR = 47 )

// 32-bit mixing function. func mix2(h uint32, k uint32) (uint32, uint32) { k = M k ^= k >> R k = M h *= M h ^= k return h, k }

// The original MurmurHash2 32-bit algorithm by Austin Appleby. func MurmurHash2(data []byte, seed uint32) (h uint32) { var k uint32

// Initialize the hash to a 'random' value
h = seed ^ uint32(len(data))

// Mix 4 bytes at a time into the hash
for l := len(data); l >= 4; l -= 4 {
    k = uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16 | uint32(data[3])<<24
    h, k = mix2(h, k)
    data = data[4:]
}

// Handle the last few bytes of the input array
switch len(data) {
case 3:
    h ^= uint32(data[2]) << 16
    fallthrough
case 2:
    h ^= uint32(data[1]) << 8
    fallthrough
case 1:
    h ^= uint32(data[0])
    h *= M
}

// Do a few final mixes of the hash to ensure the last few bytes are well incorporated
h ^= h >> 13
h *= M
h ^= h >> 15

return

}


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1164 次点击  
加入收藏 微博
7 回复  |  直到 2018-09-29 10:03:28
jingyugao
jingyugao · #1 · 7年之前

根据假设,j=9的routine先运行,若不发生抢占式调度,接着依次是012345678,最后的打印结果是9012345678 如果发生调度,那么根据时间来看,0是最先打印的,接着是123456789,因为hash操作比较费时间。 但是实际结果很奇怪。当循环的常数比较大时,结果是091234567.好像是抢占式调度了 当常数较小时,是9012345678,应该是没有抢占 当常数在某个范围内时,打印的结果是乱序的

alphayan
alphayan · #2 · 7年之前

go的说明原文能贴出来吗?想看看。

jingyugao
jingyugao · #3 · 7年之前
alphayanalphayan #2 回复

go的说明原文能贴出来吗?想看看。

记不清了 大致是这样的

alphayan
alphayan · #4 · 7年之前
jingyugaojingyugao #3 回复

#2楼 @alphayan 记不清了 大致是这样的

我也记得在哪看过这个说法,但是不是原文,是某篇博客。想找原文呼应一下。

sheepbao
sheepbao · #5 · 7年之前

关于goroutine的执行顺序官方文档肯定不会说谁先谁后,只会告诉你不要假设他们谁先谁后,因为并发就是这样规定的。不知道你假定goroutine的执行顺序有何意义?当然按照目前的runtime实现,指定一个P,创建少量的goroutine,是会先运行最后一个goroutinue,剩下的按照顺序依次运行。因为P的结构中有runnext字段用来保存最后新建的goroutine,M去找G来运行的时候也是优先找p的runnext。 但是这仅仅goroutine的没被抢占,M还未执行P本地队列中的G。如果你试试创建大量的G,就会发现goroutine的执行顺序并不符合你的说明。 详细的实现需要看runtime的具体代码,有兴趣可以一起阅读 https://github.com/sheepbao/golang_runtime_reading, 里面有我注释的golang 调度实现,可以回答你的问题。

sheepbao
sheepbao · #6 · 7年之前
jingyugao
jingyugao · #7 · 7年之前
sheepbaosheepbao #5 回复

关于goroutine的执行顺序官方文档肯定不会说谁先谁后,只会告诉你不要假设他们谁先谁后,因为并发就是这样规定的。不知道你假定goroutine的执行顺序有何意义?当然按照目前的runtime实现,指定一个P,创建少量的goroutine,是会先运行最后一个goroutinue,剩下的按照顺序依次运行。因为P的结构中有runnext字段用来保存最后新建的goroutine,M去找G来运行的时候也是优先找p的runnext。 但是这仅仅goroutine的没被抢占,M还未执行P本地队列中的G。如果你试试创建大量的G,就会发现goroutine的执行顺序并不符合你的说明。 详细的实现需要看runtime的具体代码,有兴趣可以一起阅读 https://github.com/sheepbao/golang_runtime_reading, 里面有我注释的golang 调度实现,可以回答你的问题。

嗯,我是想学习一下内部调度原理,代码层面不会依赖这个顺序,

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传