在java中,我们一般执行多线程任务的时候会启动一个线程池,然后设置线程池的大小,随后再把所有的任务放到线程池里面执行。
那么在go里面呢?其实也会有这样的业务场景,那么如何来实现呢?
其实在go里面执行的方式和java语言中的思维是一样的,分为以下几个步骤:
1、创建管道(相当于创建线程池) 2、把管道添加到同步等待组(相当于准备异步执行) 3、创建可执行的异步线程,并且把异步线程放到管道里面去(相当于创建thread,然后把thread放到线程池里面去) 4、创建子任务,把子任务放入排队的thread里面去,挨个执行 5、创建关闭指令,关闭的时候通知所有的thread退出 6、同步线程组等待所有thread执行task,且执行完毕后进行所有资源的释放
根据上面几个步骤,我们可以编写一个示例代码来演示下,完整示例代码及注释如下:
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
var (
wg sync.WaitGroup //同步等待组,它能够一直等到所有的 goroutine 执行完成,并且阻塞主线程的执行,直到所有的 goroutine 执行完成
workerCount int32 = 3 // 你想要的goroutine数量
taskCount int32 = 10 // 总的任务数量
tasksProcess int32 // 已处理的任务数量
lock sync.Mutex
)
/*
*
这里是执行的所有子任务的task信息
*/
func worker(id int, taskChan chan int) {
//每做完一个任务,标记下完成
defer wg.Done()
for {
task, more := <-taskChan
if !more {
//如果没有待处理的任务,直接退出即可。
fmt.Printf("当前执行线程没有可执行的任务,直接退出,id是:%d .\n", id)
return
}
// 模拟任务处理时间
time.Sleep(100 * time.Millisecond)
//使用lock模拟计数
lock.Lock()
atomic.AddInt32(&tasksProcess, 1)
fmt.Printf("当前执行线程id: %d 正在处理的taskid是: %d\n", id, task)
lock.Unlock()
}
}
func main() {
//创建管道,相当于java中创建一个线程池,这个线程池里可以放workerCount个执行线程
taskChan := make(chan int, workerCount) // 缓冲区大小等于workerCount
//把子任务添加到同步等待组里面。
wg.Add(int(workerCount))
//创建workerCount执行线程
for i := 0; i < int(workerCount); i++ {
go worker(i, taskChan)
}
//创建子线程任务,把它放到管道里面,相当于java中,把任务放到执行线程里面开始排队执行
for i := 0; i < int(taskCount); i++ {
taskChan <- i
}
//最后把管道给关闭掉,关闭管道的时候会通知所有的执行线程退出。
close(taskChan) // 关闭channel,通知所有worker退出
//同步等待组等待所有的go routime执行完成
wg.Wait()
//子线程执行完成之后打印输出一下。
fmt.Println("所有任务全部执行完毕")
}最后我们运行一下代码看看效果:
这里的结果与java中实现多线程看到的效果是一样的。
本文主要是按照java的惯例,在go语言中实现相关的逻辑。通过测试样例,对于转go语言的同学来说也比较直观明了。










还没有评论,来说两句吧...