gy123
V2EX  ›  问与答

通过这段 Golang 代码,有点疑问

  •  
  •   gy123 · Dec 24, 2021 · 1459 views
    This topic created in 1604 days ago, the information mentioned may be changed or developed.

    以下代码可以做到所有协程睡眠 3 秒后直接输出;

    楼主是写 java 的,在想 java 要怎么能实现 go 通过协程实现的这个例子呢? (1)直接使用 100000 个线程执行,那内存占用和上下文切换太恐怖; (2)使用线程池一类的,参数设置不到位,根据原理只能一部分一部分执行,想全部执行,得参考(1)的线程数量...

    有啥能实现吗?难道类似这就是 go 协程的魅力?

    package main
    
    import (
    	"strconv"
    	"time"
    )
    
    func say0(str string) {
    	time.Sleep(3 * time.Second)
    	println(str)
    }
    
    func main() {
    	for i := 0; i < 100000; i++ {
    		go say0("协程" + strconv.Itoa(i))
    	}
    
    	time.Sleep(1000 * time.Second)
    }
    
    
    meiyoumingzi6
        1
    meiyoumingzi6  
       Dec 24, 2021 via iPhone
    其实楼主写的这段代码有大坑🤪
    这里 go 不是直接就执行了,所以等到执行的时候 i 的数值是不确定的,另外因为这个 go 执行的太短了,所以在 1000 秒(对不起我一开始看成了 1000 毫秒)是可以执行完的,但是这样是不对的,应该使用 wait group 来处理这个事情,最后 可以无脑 go 吗?理论上来说是可以开启无限个的,但是开太多调度就会很繁忙,还有如果是并发处理请求的话,可能会给对方打挂了,还有一个就是 go 的 func 如果 panic 就会导致整个进程挂掉,所以最好是启动的时候 recover 一下






    回到问题上,如果让我换个语言,我会选择线程池,配合 queue 来做😁
    leon0318
        2
    leon0318  
       Dec 24, 2021 via iPhone
    楼主有没有想过协程的应用场景? 照你这么说,java 早被打趴下了,然而……🐶
    anonymousar
        3
    anonymousar  
       Dec 24, 2021
    线程池怎么就做不到了? push 100k 个 task/future 进去不就行了? 这跟线程数有啥关系? go 难道不用 thread 跑任务了?
    watzds
        4
    watzds  
       Dec 24, 2021
    我理解就是应用层线程,应用层自己实现

    直接用普通线程池,任务互相的话依赖容易死锁,或者阻塞浪费资源,用 java 8 ForkJoinPool 好点
    gy123
        5
    gy123  
    OP
       Dec 24, 2021 via iPhone
    @meiyoumingzi6 学习了
    gy123
        6
    gy123  
    OP
       Dec 24, 2021 via iPhone
    @anonymousar push 到队列?然而每次拿出来多少任务执行,还是依靠设置的线程数吧。我知道 go 也是线程,但是这个场景你能做出来吗。可以写写试试
    gy123
        7
    gy123  
    OP
       Dec 24, 2021 via iPhone
    @watzds 就是我写的这个例子,不知道 java 怎么实现
    gy123
        8
    gy123  
    OP
       Dec 24, 2021 via iPhone
    我就想知道 java 怎么保证线程数很少的情况下,得到 go 执行的效果。。
    iamzuoxinyu
        9
    iamzuoxinyu  
       Dec 24, 2021
    其实跟你自己实现个带任务窃取的线程池是一样的。
    gy123
        10
    gy123  
    OP
       Dec 24, 2021 via iPhone
    @anonymousar 还是说你想表达的是用延迟线程池,设置个延迟时间然后队列里的任务全部执行。。
    gy123
        11
    gy123  
    OP
       Dec 24, 2021 via iPhone
    @leonme 场景可能就是大 io 处理上,就算很多轻量级协程,要比线程好太多吧
    leon0318
        12
    leon0318  
       Dec 24, 2021 via iPhone
    @gy123 然后你再想下正常业务瓶颈是在 io 上还是在 cpu 的调度(线程数)上? 所以你就明白为啥 go 一般都是做些网关代理中间件啥的
    gy123
        13
    gy123  
    OP
       Dec 24, 2021
    @leonme 嗯,这里的 io 特指网络 io.受教了
    gy123
        14
    gy123  
    OP
       Dec 24, 2021
    此贴终结...楼主忘记了 ScheduledExecutorService
    gy123
        15
    gy123  
    OP
       Dec 24, 2021
    或者自己实现类似于拿出任务判断时间....被 go 这种 sleep 写法迷惑了
    anonymousar
        16
    anonymousar  
       Dec 24, 2021
    @gy123 延迟跟队列跟线程池都无关 io 密集型任务 goroutine 就好处理么? 明明 epoll 才更优
    meiyoumingzi6
        17
    meiyoumingzi6  
       Dec 24, 2021
    #1
    emmm 上面说的有点问题, 你这里是传的参数 , 所以 str 不会有问题

    @gy123
    无脑 go 版本
    ```golang
    package main

    import (
    "fmt"
    "strconv"
    "sync"
    "time"
    )

    func say0(str string, wg *sync.WaitGroup) {
    defer func() {
    _ = recover()
    // 处理异常
    wg.Done()
    }()
    time.Sleep(3 * time.Second)
    fmt.Println(str)
    }

    func main() {
    wg := &sync.WaitGroup{}
    for i := 0; i < 100000; i++ {
    wg.Add(1)
    go say0("协程" + strconv.Itoa(i), wg)
    }
    wg.Wait()

    }
    ```


    控制协程数量版本

    ```golang
    package main

    import (
    "fmt"
    "strconv"
    "sync"
    "time"
    )

    func say0(c chan int, wg *sync.WaitGroup) {
    defer func() {
    _ = recover()
    // 处理异常
    wg.Done()
    }()
    for {
    time.Sleep(1 * time.Second)
    i, ok := <-c
    if ok {
    fmt.Println("协程" + strconv.Itoa(i))
    } else {
    fmt.Println("协程结束")
    break
    }
    }

    }

    func main() {
    var c chan int
    c = make(chan int, 10)
    wg := &sync.WaitGroup{}
    for i := 0; i < 10; i++ {
    wg.Add(1)
    go say0(c, wg)
    }
    for i := 0; i < 100; i++ {
    c <- i
    }
    close(c)
    fmt.Printf("close")
    wg.Wait()
    }

    ```
    gy123
        18
    gy123  
    OP
       Dec 25, 2021 via iPhone
    [ [码上开学] 到底什么是「非阻塞式」挂起?协程真的比线程更轻量级吗?-哔哩哔哩] https://b23.tv/YyQhA3Q

    我悟了,最后一段说的,的确就是我的误解
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3112 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 113ms · UTC 03:39 · PVG 11:39 · LAX 20:39 · JFK 23:39
    ♥ Do have faith in what you're doing.