以下代码可以做到所有协程睡眠 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)
}
1
meiyoumingzi6 2021-12-24 18:23:19 +08:00 via iPhone
其实楼主写的这段代码有大坑🤪
这里 go 不是直接就执行了,所以等到执行的时候 i 的数值是不确定的,另外因为这个 go 执行的太短了,所以在 1000 秒(对不起我一开始看成了 1000 毫秒)是可以执行完的,但是这样是不对的,应该使用 wait group 来处理这个事情,最后 可以无脑 go 吗?理论上来说是可以开启无限个的,但是开太多调度就会很繁忙,还有如果是并发处理请求的话,可能会给对方打挂了,还有一个就是 go 的 func 如果 panic 就会导致整个进程挂掉,所以最好是启动的时候 recover 一下 回到问题上,如果让我换个语言,我会选择线程池,配合 queue 来做😁 |
2
leonme 2021-12-24 18:25:39 +08:00 via iPhone
楼主有没有想过协程的应用场景? 照你这么说,java 早被打趴下了,然而……🐶
|
3
anonymousar 2021-12-24 18:34:53 +08:00
线程池怎么就做不到了? push 100k 个 task/future 进去不就行了? 这跟线程数有啥关系? go 难道不用 thread 跑任务了?
|
4
watzds 2021-12-24 18:38:57 +08:00
我理解就是应用层线程,应用层自己实现
直接用普通线程池,任务互相的话依赖容易死锁,或者阻塞浪费资源,用 java 8 ForkJoinPool 好点 |
5
gy123 OP @meiyoumingzi6 学习了
|
6
gy123 OP @anonymousar push 到队列?然而每次拿出来多少任务执行,还是依靠设置的线程数吧。我知道 go 也是线程,但是这个场景你能做出来吗。可以写写试试
|
8
gy123 OP 我就想知道 java 怎么保证线程数很少的情况下,得到 go 执行的效果。。
|
9
iamzuoxinyu 2021-12-24 18:49:20 +08:00
其实跟你自己实现个带任务窃取的线程池是一样的。
|
10
gy123 OP @anonymousar 还是说你想表达的是用延迟线程池,设置个延迟时间然后队列里的任务全部执行。。
|
12
leonme 2021-12-24 19:30:15 +08:00 via iPhone
@gy123 然后你再想下正常业务瓶颈是在 io 上还是在 cpu 的调度(线程数)上? 所以你就明白为啥 go 一般都是做些网关代理中间件啥的
|
14
gy123 OP 此贴终结...楼主忘记了 ScheduledExecutorService
|
15
gy123 OP 或者自己实现类似于拿出任务判断时间....被 go 这种 sleep 写法迷惑了
|
16
anonymousar 2021-12-24 19:59:28 +08:00
@gy123 延迟跟队列跟线程池都无关 io 密集型任务 goroutine 就好处理么? 明明 epoll 才更优
|
17
meiyoumingzi6 2021-12-24 20:01:05 +08:00
#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() } ``` |
18
gy123 OP |