在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语言的同学来说也比较直观明了。
还没有评论,来说两句吧...