利用go語(yǔ)言編寫(xiě)一個(gè)并發(fā)包
寫(xiě)在前面
這是一個(gè)只需要用50行代碼(核心代碼只有15行)實(shí)現(xiàn)的極其簡(jiǎn)單(原理簡(jiǎn)單、使用方法簡(jiǎn)單、功能簡(jiǎn)單)的go包mini_parallel_job,適合大部分并發(fā)任務(wù),開(kāi)箱即用。
代碼
package mini_parallel_job
import (
"fmt"
"sync"
)
type JobType func()
type JobPool interface {
AddJob(jobType JobType)
Wait()
}
type jobPool struct {
jobs []JobType
}
// 添加任務(wù)
func (j *jobPool) AddJob(job JobType) {
j.jobs = append(j.jobs, job)
}
// 開(kāi)始并且等待任務(wù)
func (j *jobPool) Wait() {
var wg sync.WaitGroup
wg.Add(len(j.jobs))
for i := range j.jobs {
jJob := j.jobs[i]
go func() {
defer func() {
wg.Done()
if err := recover(); err != nil {
fmt.Printf("err:%+v", err)
}
}()
jJob()
}()
}
wg.Wait()
}
func NewJobPool() JobPool {
return &jobPool{
jobs: make([]JobType, 0),
}
}
壓測(cè)
package mini_parallel_job
import (
"testing"
)
const (
Count = 10
)
// 并行任務(wù)
func parallelJob() {
jobPool := NewJobPool()
for i := 0; i < Count; i++ {
jobPool.AddJob(func() {
_ = fib(10)
})
}
jobPool.Wait()
}
// 串行任務(wù)
func serialJob() {
for i := 0; i < Count; i++ {
_ = fib(10)
}
}
// 任務(wù)
func fib(n int) int {
if n == 0 || n == 1 {
return n
}
return fib(n-2) + fib(n-1)
}
// 性能測(cè)試
func BenchmarkSerialJob(b *testing.B) {
for i := 0; i < b.N; i++ {
serialJob()
}
}
func BenchmarkParallelJob(b *testing.B) {
for i := 0; i < b.N; i++ {
parallelJob()
}
}
/*
BenchmarkSerialJob-12 298855 3756 ns/op
BenchmarkParallelJob-12 117189 8710 ns/op
*/
example
package main
import (
"fmt"
mini_parallel_job "mini-parallel-job"
"time"
)
const (
JobCount = 10
)
func main() {
// 串行執(zhí)行
begin1 := time.Now()
for i := 0; i < JobCount; i++ {
fib(40)
}
fmt.Println(time.Since(begin1))
// 并行執(zhí)行
begin2 := time.Now()
parallelJob := mini_parallel_job.NewJobPool()
for i := 0; i < JobCount; i++ {
parallelJob.AddJob(func() {
fib(40)
})
}
parallelJob.Wait()
fmt.Println(time.Since(begin2))
/*
結(jié)果:
7.335989407s
1.112108503s
*/
}
// 任務(wù)
func fib(n int) int {
if n == 0 || n == 1 {
return n
}
return fib(n-2) + fib(n-1)
}
總結(jié)
這段代碼僅僅實(shí)現(xiàn)使用go rountine實(shí)現(xiàn)并發(fā),sync.WaitGroup實(shí)現(xiàn)等待。
在大多數(shù)場(chǎng)景中,只需要并發(fā),并不關(guān)心并發(fā)量是多少,大多數(shù)程序員也是使用Wait函數(shù)那段代碼實(shí)現(xiàn)的(至少作者在項(xiàng)目中看到都是這樣的,并且有多處相同的代碼,基于此場(chǎng)景封裝了一下)。
如果要實(shí)現(xiàn)復(fù)雜一點(diǎn)的場(chǎng)景,比如控制最大并發(fā)量,可以稍微對(duì)上述代碼做一些修改,Wait函數(shù)中加一個(gè)指定大小的chan來(lái)控制。或者參考作者另外一個(gè)對(duì)go并發(fā)的封裝gopool,使用master-worker模式實(shí)現(xiàn)的并發(fā)控制。
到此這篇關(guān)于利用go語(yǔ)言編寫(xiě)一個(gè)并發(fā)包的文章就介紹到這了,更多相關(guān)go并發(fā)包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang中HTTP服務(wù)的分析與設(shè)計(jì)詳解
這篇文章主要介紹了Golang中HTTP服務(wù)的分析與設(shè)計(jì),HTTP服務(wù)是實(shí)現(xiàn)Web應(yīng)用程序的重要組成部分,為了實(shí)現(xiàn)高效可擴(kuò)展的Web應(yīng)用程序,需要對(duì)HTTP服務(wù)進(jìn)行分析與設(shè)計(jì),需要的朋友可以參考下2023-05-05
golang遍歷處理map時(shí)的常見(jiàn)性能陷阱與解決方法
這篇文章主要為大家詳細(xì)介紹了Golang中有關(guān)循環(huán)處理map時(shí)的性能優(yōu)化,本文主要介紹了常見(jiàn)的三種場(chǎng)景,文中的示例代碼講解詳細(xì),需要的可以了解下2025-05-05
Go實(shí)現(xiàn)快速生成固定長(zhǎng)度的隨機(jī)字符串
這篇文章主要為大家詳細(xì)介紹了怎樣在Go中簡(jiǎn)單快速地生成固定長(zhǎng)度的隨機(jī)字符串,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以學(xué)習(xí)一下2022-10-10
解決golang 反射interface{}做零值判斷的一個(gè)重大坑
這篇文章主要介紹了解決golang 反射interface{}做零值判斷的一個(gè)重大坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
Go泛型實(shí)戰(zhàn)教程之如何在結(jié)構(gòu)體中使用泛型
這篇文章主要介紹了Go泛型實(shí)戰(zhàn)教程之如何在結(jié)構(gòu)體中使用泛型,根據(jù)Go泛型使用的三步曲提到的:類型參數(shù)化、定義類型約束、類型實(shí)例化我們一步步來(lái)定義我們的緩存結(jié)構(gòu)體,需要的朋友可以參考下2022-07-07
Go庫(kù)實(shí)現(xiàn)Kafka消息的發(fā)送與接收(docker和k3s安裝kafka)
文章介紹使用docker在宿主機(jī)映射容器9092端口部署k3s,并使用Go庫(kù)實(shí)現(xiàn)Kafka消息的發(fā)送與接收,涉及segmentio/kafka-gogo、saramago和sarama等客戶端庫(kù)的應(yīng)用場(chǎng)景2025-09-09

