Reputation: 305
There are several channels to monitor, their type are different and irrelevant(since we only care about len and cap), but golang compiler does not accept following code, whatever T is:
func monitorChan(ch chan T) {
for {
if len(ch) == cap(ch) {
log.Warn("log")
}
time.Sleep(chanMonitorInterval)
}
}
it shows error:
cannot use ch (type chan []byte) as type chan interface {} in argument to monitorChan.
How can this function be modified to write once monitor every channel?
Here is my code:
package main
import (
"fmt"
"time"
)
func monitorChan(ch chan interface{}) {
for {
if len(ch) == cap(ch) {
fmt.Println("log")
}
time.Sleep(1 * time.Second)
}
}
func main() {
ch := make(chan []byte, 100)
go monitorChan(ch)
// actual things below ...
}
Playground: https://play.golang.org/p/t7T28IpLNAs
Upvotes: 1
Views: 568
Reputation: 45120
This is now trivial to accomplish, using type parameters:
func monitorChan[T any](ch chan T) {
for {
if len(ch) == cap(ch) {
log.Warn("log")
}
time.Sleep(chanMonitorInterval)
}
}
Type inference also allows to infer the type parameter T
from the concrete type of the function argument, so the code in main
doesn't even need to be rewritten:
func main() {
ch := make(chan []byte, 100)
go monitorChan(ch) // T instantiated as []byte
// actual things below ...
}
Upvotes: 2
Reputation: 166835
Use reflection. For example,
package main
import (
"log"
"reflect"
"time"
)
func monitorChan(ch interface{}, intvl time.Duration) {
v := reflect.ValueOf(ch)
if v.Kind() != reflect.Chan {
return
}
c := v.Cap()
if c == 0 {
return
}
for {
if l := v.Len(); l == c {
log.Printf("log: len(%d) cap(%d)", l, c)
}
time.Sleep(intvl)
}
}
func main() {
log.Print("main")
c := make(chan []byte, 10)
var chanMonitorInterval = 1 * time.Second
go monitorChan(c, chanMonitorInterval)
log.Print("monitor")
time.Sleep(5 * chanMonitorInterval)
for len(c) != cap(c) {
c <- []byte{}
}
log.Print("len(c) == cap(c)")
time.Sleep(3 * chanMonitorInterval)
<-c
log.Print("len(c) < cap(c)")
time.Sleep(5 * chanMonitorInterval)
log.Print("main")
}
Playground: https://play.golang.org/p/c5VhIIO0pik
Output:
2009/11/10 23:00:00 main
2009/11/10 23:00:00 monitor
2009/11/10 23:00:05 len(c) == cap(c)
2009/11/10 23:00:06 log: len(10) cap(10)
2009/11/10 23:00:07 log: len(10) cap(10)
2009/11/10 23:00:08 log: len(10) cap(10)
2009/11/10 23:00:08 len(c) < cap(c)
2009/11/10 23:00:13 main
References:
The Go Blog: The Laws of Reflection
Upvotes: 3
Reputation: 12685
Create an interface{}
type channel and pass any type wrapping around interface{}
, then fetch the use type assert on receiving end.
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func monitorChan(ch chan interface{}) {
val := <-ch
fmt.Println(string(val.(interface{}).([]uint8)))
wg.Done()
}
func main() {
ch := make(chan interface{}, 100)
wg.Add(1)
ch <- []byte("hello")
go monitorChan(ch)
wg.Wait()
// actual things below ...
}
Working code on Go Playground
Edited :- you can also go for reflect package to get the values of channels after wrapping the channels inside interface{}
package main
import (
"fmt"
"sync"
"reflect"
)
var wg sync.WaitGroup
func monitorChan(i interface{}) {
defer wg.Done()
v := reflect.ValueOf(i)
fmt.Printf("%s size: %d/%d\n", v.Kind(), v.Len(), v.Cap())
}
func main() {
ch := make(chan []byte, 100)
wg.Add(1)
go monitorChan(ch)
wg.Wait()
// actual things below ...
}
Upvotes: -1