处理具有固定数量工作人员的无休止队列中的作业

时间:2014-03-23 21:31:08

标签: concurrency go

这是我的头脑,我无法弄清楚如何解决它;

  • 我希望在parallell中运行固定数量N的goroutines
  • 从一个永无止境的队列中,我将获取有关要处理的作业的X msg
  • 我想让N goroutines处理这些X作业,只要其中一个例程没有其他任何事情要做,我想从无休止的队列中获取另一个X作业

以下答案中的代码(请参阅url)可以很好地处理任务,但是一旦任务列表为空,工作人员就会死亡,我希望它们保持活跃状态​​,并以某种方式通知主代码它们不能正常工作所以我可以获取更多的工作来填充任务列表中的任务

How would you define a pool of goroutines to be executed at once in Golang?

使用user:来自下面的Jsor示例代码,我尝试创建一个简单的程序,但我很困惑。

import (
    "fmt"
    "strconv"
)

//workChan - read only that delivers work
//requestChan - ??? what is this
func Worker(myid string, workChan <- chan string, requestChan chan<- struct{}) {
    for {
        select {
        case work := <-workChan:
            fmt.Println("Channel: " + myid + " do some work: " + work)
        case requestChan <- struct{}{}:
            //hm? how is the requestChan used?
        }
    }
}

func Logic(){

    workChan := make(chan string)
    requestChan := make(chan struct{})

    //Create the workers
    for i:=1; i < 5; i++ {
        Worker( strconv.Itoa( i), workChan, requestChan)
    }

    //Give the workers some work
    for i:=100; i < 115; i++ {
        workChan<- "workid"+strconv.Itoa( i)
    }

}

2 个答案:

答案 0 :(得分:2)

这是select声明的用途。

func Worker(workChan chan<- Work, requestChan chan<- struct{}) {
    for {
        select {
        case work := <-workChan:
            // Do work
        case requestChan <- struct{}{}:
        }
    }
}

这名工人将永远奔跑。如果工作可用,它将从工作人员频道中提取。如果没有任何遗漏,它将发送请求。

不是因为它永远运行,如果你想杀死一个工人你需要做其他事情。一种可能性是始终使用workChan检查ok,如果该通道关闭,则退出该功能。另一种选择是为每个工人使用单独的退出渠道。

答案 1 :(得分:0)

other solution you posted相比,您只需要(首先)关闭频道,然后继续向其投放内容。

然后您需要回答以下问题:一旦其中一名工作人员拥有(a),您只需>从队列中获取下一个X项目是绝对必要的“没有更多的事情要做”(或者,一旦前X个项目被完全处理或分配给工人,那么同样如此);或(b)如果您将第二组X项目保留在内存中,并在需要新工作项目时将它们提供给工作人员,这是否可以?

据我所知,只有(a)需要你想知道的 requestChan (见下文)。对于(b),以下简单的内容就足够了:

# B version

type WorkItem int

const (
  N = 5  // Number of workers
  X = 15 // Number of work items to get from the infinite queue at once
)

func Worker(id int, workChan <-chan WorkItem) {
  for {
    item := <-workChan
    doWork(item)
    fmt.Printf("Worker %d processes item #%v\n", id, item)
  }
}

func Dispatch(workChan chan<- WorkItem) {
  for {
    items := GetNextFromQueue(X)

    for _, item := range items {
      workChan <- item
      fmt.Printf("Dispatched item #%v\n", item)
    }
  }
}

func main() {
  workChan := make(chan WorkItem) // Shared amongst all workers; could make it buffered if GetNextFromQueue() is slow.

  // Start N workers.
  for i := 0; i < N; i++ {
    go Worker(i, workChan)
  }

  // Dispatch items to the workers.
  go Dispatch(workChan)

  time.Sleep(20 * time.Second) // Ensure main(), and our program, finish.
}

(我已经上传到游乐场full working solution for (b)。)

对于(a),工作人员改变说:做工作,如果没有更多的工作,请告诉调度员通过获得更多reqChan 通讯渠道。 “或”是通过 select 实现的。然后,调度程序 reqChan 上等待,然后再拨打GetNextFromQueue()。这是更多的代码,但确保您可能感兴趣的语义。(但以前的版本总体上更简单。)

# A version

func Worker(id int, workChan <-chan WorkItem, reqChan chan<- int) {
  for {
    select {
    case item := <-workChan:
      doWork(item)
      fmt.Printf("Worker %d processes item #%v\n", id, item)
    case reqChan <- id:
      fmt.Printf("Worker %d thinks they requested more work\n", id)
    }
  }
}

func Dispatch(workChan chan<- WorkItem, reqChan <-chan int) {
  for {
    items := GetNextFromQueue(X)

    for _, item := range items {
      workChan <- item
      fmt.Printf("Dispatched item #%v\n", item)
    }

    id := <-reqChan
    fmt.Printf("Polling the queue in Dispatch() at the request of worker %d\n", id)
  }
}

(我还上传到了游乐场full working solution for (a)。)