Search code examples
for-loopconcurrencygochannel

Using channels in Go created by a 'for' loop


Can channels created in a for loop be interchangeably used by subroutines running concurrently from that for loop?

Pseudocode is below:

for i := range Map {
    channel := make(chan my_type, buff_size)

    go subroutine(Map[i], channel)
}

func subroutine(name valueType, channel channelType) {
    // Stuff here
}

Is there a way were subroutine(Map[0]) for example, could access another channel created during another iteration of the for loop, i.e., channel of subroutine(Map[1])?


Context: I'm currently working on a project where I have to simulate different populations of cells. Each cell has the ability to divide, differentiate, etc. To replicate the real system, the different populations have to run concurrently with one another. The issue is that I have to insert/remove a cell of a specific population type while working on a different population, this is where the channels come into play. I was thinking of running the populations concurrently each of them having an associated channel. And this is why I'm asking if we can use channels created in different for loop iterations.


Here is some of my code to support my context description with comments explaining the different elements. I've included channels, but I have no idea if it works. I'm hoping it helps with understanding what I'm trying to do:

func main() {
    // Where envMap is a map[int]Population and Population is a struct
    envMap := initialiseEnvironment(envSetupInfo)

    // General simulation loop
    for i := 0; i < 10; i++ {
        // Loop to go through all envMap elements in parallel
        for eachKey := range envMap {
            channel := make(chan type)
            go simulateEnv(envMap[eachKey])
        }
    }
}

func simulateEnv(cellPopulation Population, channel chan) {
    // Each Population has a map[int]Cell where Cell is a struct with cell properties
    cellMap := cellPopulation.cellMap

    for eachCell := range cellMap {
        go divisionTransition(eachCell, channel)
    }
}

Solution

  • Assuming each element of the map is a struct, you could make a field to hold references to other channels. For example, if you wanted each element of your map to have a reference to the previous channel, you could do something like this:

    // assumes that Map[whatever] is a struct with a "lastChan" field
    var lastRef = chan my_type
    
    
    for i := range Map {
          channel := make(chan my_type, buff_size)
          if(lastRef != nil){
              Map[i].lastChan = lastRef
          }
    
          go subroutine(Map[i], channel)
          lastRef = channel
    }
    
    func subroutine(name valueType, channel channelType) {
        //stuff here can access the previous channel with name.lastChan
    }
    

    Depending on what you want to do and which channels you need access to, you may wish to play around with the looping or even do mutliple loops.