goroutines花的时间太长了

goroutines花的时间太长了,go,Go,我的理解是,对于无缓冲通道(jobs),您需要一个发送者和接收者,而我有一个发送者和接收者,但我的代码顺序有点错误,需要很长时间才能完成。 我错过了什么 const numWorkers = 5 type workerJob struct { FirstID string SecondID string } func worker(ctx *gin.Context, fs *firestore.Client, jobs <-chan *workerJob, done

我的理解是,对于无缓冲通道(
jobs
),您需要一个发送者和接收者,而我有一个发送者和接收者,但我的代码顺序有点错误,需要很长时间才能完成。
我错过了什么

const numWorkers = 5
type workerJob struct {
    FirstID   string
    SecondID string
}

func worker(ctx *gin.Context, fs *firestore.Client, jobs <-chan *workerJob, done chan<- bool) {
    for job := range jobs {
        firstID := job.FirstID
        secondID := job.SecondID
        if err := saveUpdate(ctx, firstID, secondID, fs); err != nil {
            // handle error
        }
    }
    done <- true
}

func UpdateSomething(ctx *gin.Context) {
    fs, err := firestore.NewClient(ctx, "some_ID")
    if err != nil {
        // handle error
    }
    defer fs.Close()

    docsnaps, err := fs.CollectionGroup("someCollection").Where("someCondition", "==", true).Documents(ctx).GetAll()
    if err != nil {
        // handle error
    }
    uniqueSomethings := make(map[string]struct{})
    jobs := make(chan *workerJob)
    done := make(chan bool, numWorkers)
    for w := 1; w <= numWorkers; w++ {
         go worker(ctx, fs, jobs, done)
    }
    for _, docsnap := range docsnaps {
        var someType SomeType
        err := docsnap.DataTo(&someType)
        if err != nil { 
            // handle error
        }
        for _, prop := range someType.prop {
            if strings.Contains(prop.Name, "someString") {
                someID := prop.Name[strings.LastIndex(prop.Name, ":")+1:]
                if _, ok := uniqueSomethings[someID]; !ok {
                    uniqueSomethings[someID] = struct{}{}
                    job := &workerJob{
                        FirstID: dashboard.CustomerID,
                        SecondID:   someID[strings.Index(someID, "_")+1:],
                    }
                    jobs <- job
                }
            }
        }
    }
    close(jobs)
    for i := 1; i <= numWorkers; i++ {
        select {
        case <-done:
        }
    }
    return
}
const numWorkers=5
类型workerJob结构{
第一个ID字符串
二次字符串
}

func工人(ctx*gin.Context,fs*firestore.Client,jobs我不完全理解为什么,但我已经能够将时间缩短6倍!我决定创建一个作业片段,然后创建一个具有预定义容量的频道-该片段的长度,然后在该片段上循环,并将作业发送到该频道。下面是它的外观:

func UpdateSomething(ctx *gin.Context) {
    fs, err := firestore.NewClient(ctx, "some_ID")
    if err != nil {
        // handle error
    }
    defer fs.Close()

    docsnaps, err := fs.CollectionGroup("someCollection").Where("someCondition", "==", true).Documents(ctx).GetAll()
    if err != nil {
        // handle error
    }
    uniqueSomethings := make(map[string]struct{})
    jobsArr := make([]*workerJob, 0)
   
    for _, docsnap := range docsnaps {
        var someType SomeType
        err := docsnap.DataTo(&someType)
        if err != nil { 
            // handle error
        }
        for _, prop := range someType.prop {
            if strings.Contains(prop.Name, "someString") {
                someID := prop.Name[strings.LastIndex(prop.Name, ":")+1:]
                if _, ok := uniqueSomethings[someID]; !ok {
                    uniqueSomethings[someID] = struct{}{}
                    job := &workerJob{
                        FirstID: dashboard.CustomerID,
                        SecondID:   someID[strings.Index(someID, "_")+1:],
                    }
                    jobsArr = append(jobsArr, job)
                }
            }
        }
    }
    done := make(chan bool, numWorkers)
    jobs := make(chan *workerJob, len(jobsArr))
     
    for w := 1; w <= numWorkers; w++ {
         go worker(ctx, fs, jobs, done)
    }
    for _, job := range jobsArr {
        jobs <- job
    }
    close(jobs)
    for i := 1; i <= numWorkers; i++ {
        select {
        case <-done:
        }
    }
    return
}
func updateMething(ctx*gin.Context){
fs,err:=firestore.NewClient(ctx,“some\u ID”)
如果错误!=零{
//处理错误
}
延迟fs.Close()
docsnap,err:=fs.CollectionGroup(“someCollection”).Where(“someCondition”,“true=”).Documents(ctx).GetAll()
如果错误!=零{
//处理错误
}
uniqueSomethings:=make(映射[字符串]结构{})
jobsArr:=make([]*workerJob,0)
对于u,docsnap:=范围docsnap{
var someType someType
错误:=docsnap.DataTo(&someType)
如果错误!=nil{
//处理错误
}
对于u,prop:=范围someType.prop{
if strings.Contains(prop.Name,“someString”){
someID:=prop.Name[strings.LastIndex(prop.Name,“:”)+1:]
如果u,ok:=uniqueSomethings[someID];!ok{
uniqueSomethings[someID]=struct{}{}
作业:=&workerJob{
FirstID:dashboard.CustomerID,
SecondID:someID[strings.Index(someID,“”)+1:],
}
jobsArr=append(jobsArr,job)
}
}
}
}
完成:=制造(成龙、numWorkers)
工作:=制造(chan*workerJob,len(jobsArr))

对于w:=1;w请注意“goroutine”是一个单词;-)您的代码没有明显的错误。由于作业和结果通道都是无缓冲的,因此很容易推断:
numWorkers
goroutines同时从
jobs
通道读取,因此如果您有≤
numWorkers
作业几乎会立即获得。然后事情变得更有趣,因为所有worker goroutine都将其处理结果写入一个无缓冲通道,因此它们都会等待
for
循环,该循环会耗尽
done
通道。现在请注意,直到worker goroutine设法将其结果写入
done
通道,但它无法……获得要执行的新作业,如果作业数远高于工作人员数,则一些工作人员可能会坐在那里等待结果被接受。因此,第二种想法是,您的代码存在问题:工作人员的编码方式是处理它只需要等待“<代码> NoWorks返回,这是不正确的:您需要计算提交的作业的数量并等待许多备份返回。现在考虑,无论什么代码> SavePuthOuts<代码>,都不应该是即时的,同时也有几个并发调用<代码> SavePoDeDe//Cord>你甚至可以在“fire store”的东西上自然地序列化(不管它是什么意思,听起来像一个DB引擎)。在这种情况下,再多的并行性也不能使整个事情完成得更快。@kostix the
numWorker
(5)根据设计,我只需要多达5名工人同时工作。虽然你写的东西是有帮助的。这是因为你原来的推销员只把1份工作推到了一批工人中;现在让我们考虑你的工人可以快速工作,并且在同样的时间内完成2个工作,这意味着当你推动第三个工作。您的第一个工作人员已完成,正在等待新的分配,其余的工作人员将处于空闲状态。上述假设将意味着您永远无法获得池大小的效率;现在,当您使用缓冲通道时,您的工作人员可以更快地开始工作,并在将这么多作业推到一起时一起开始工作。这有意义吗?请同时说明完成通道的ead您应该使用等待组,并在将作业添加到队列之前添加它,这样您就不需要通过在通道中接收n个输入来等待作业完成的这种黑客方式