Go Tee-Channel: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
Line 6: Line 6:
This example uses <code>orDone()</code> described in the [[Go_OR-Done-Channel_Pattern#orDone()|OR-Done-Channel Pattern]] section.
This example uses <code>orDone()</code> described in the [[Go_OR-Done-Channel_Pattern#orDone()|OR-Done-Channel Pattern]] section.
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
func tee(done <-chan interface{}, in <-chan interface{}) (_, _ <-chan interface{}) {
out1 := make(chan interface{})
out2 := make(chan interface{})
go func() {
defer close(out1)
defer close(out2)
for v := range orDone(done, in) {
var out1, out2 = out1, out2 // We use the local versions of out1 and out2, so we shadow these variables.
for i := 0; i < 2; i++ {
// We are going to use one select statement so that writes to out1 and out2 don't block each other.
// To ensure both are written to, we do it in a 2-step loop.
select {
case <-done:
case out1 <- v:
// once we've written on a channel, we set the shadowed copy to nil
// so that further writes will block and the other channel may continue
out1 = nil
case out2 <- v:
// once we've written on a channel, we set the shadowed copy to nil
// so that further writes will block and the other channel may continue
out2 = nil
}
}
}
}()
return out1, out2
}
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 23:15, 5 February 2024

Internal

Overview

This pattern allows duplicating and splitting the values coming in from a channel into two different output channels.

tee()

This example uses orDone() described in the OR-Done-Channel Pattern section.

func tee(done <-chan interface{}, in <-chan interface{}) (_, _ <-chan interface{}) {
	out1 := make(chan interface{})
	out2 := make(chan interface{})
	go func() {
		defer close(out1)
		defer close(out2)
		for v := range orDone(done, in) {
			var out1, out2 = out1, out2 // We use the local versions of out1 and out2, so we shadow these variables.
			for i := 0; i < 2; i++ {
				// We are going to use one select statement so that writes to out1 and out2 don't block each other.
				// To ensure both are written to, we do it in a 2-step loop.
				select {
				case <-done:
				case out1 <- v:
					// once we've written on a channel, we set the shadowed copy to nil
					// so that further writes will block and the other channel may continue
					out1 = nil
				case out2 <- v:
					// once we've written on a channel, we set the shadowed copy to nil
					// so that further writes will block and the other channel may continue
					out2 = nil
				}
			}
		}
	}()
	return out1, out2
}