2026年5月19日 星期二

[Go] Concurrency Patterns - Data Protected by Confinement

Data Protected by Confinement

 golang     concurrency    pattern  

Confinement ensures information is only available from one concurrent process. When this is achieved, a concurrent program is implicitly safe and no synchronization is needed.

Consider the following example.

data := []int{1, 2, 3, 4}

loopData := func(handleData chan<- int) {
	defer close(handleData)
	for _, v := range data {
		handleData <- v
	}
}

handleData := make(chan int)
go loopData(handleData)

// This line will cause deadlock
// handleData <- 5

for num := range handleData {
	fmt.Println(num)
}


If somebody adds the line handleData <- 5, the program will be deadlocked because there is another goroutine (which called loopData) was sending message to the channel handleData.

Lexical confinement can solve this problem because it uses lexical scope to expose only the correct data and concurrency primitives for multiple concurrent processes to use. It makes it impossible to do the wrong thing.

Let's update the above sample code with lexical confinemnt pattern:

data := []int{1, 2, 3, 4}

chanOwner := func() <-chan int {
	// Initiate the channel within the lexical scope of the function
	handleData := make(chan int)

	go func() {
		defer close(handleData)
		for _, v := range data {
			handleData <- v
		}
	}()
	return handleData
}

roChan := chanOwner()

for num := range roChan {
	fmt.Println(num)
}


  • The function chanOwner initiates the channel handleData in its lexical scope, and returns the readonly channel.
  • This limits the scope of write aspect of the channel to the closure that only the channel owner can write to channel, other goroutines have no chance to write but only can read from the channel.

In summary, lexical confinement has the following benefits:

  • We don't have to do the data synchorization concurrent code, because synchorization comes a cost and developer may do it wrong without any compiler error.
  • The concurrent code will be simplier to understand than without lexically confined variables and scopes.
  • Sometimes it's hard to establish confinement and we have to fall back to Go concurrency primitives.

沒有留言:

張貼留言