有几个要监视的通道,它们的类型不同且不相关(因为我们只关心len和cap),但是golang编译器不接受以下代码,无论T是什么:

1
2
3
4
5
6
7
8
func monitorChan(ch chan T) {
    for {
        if len(ch) == cap(ch) {
            log.Warn("log")
        }
        time.Sleep(chanMonitorInterval)
    }
}

它显示错误:

cannot use ch (type chan []byte) as type chan interface {} in argument
to monitorChan.

如何修改此功能以在每个通道监控一次写入一次?

这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 ...
}

游乐场:https://play.golang.org/p/t7T28IpLNAs

  • 请在使用适当的参数及其类型调用函数的地方张贴代码,以重新创建您遇到的错误
  • 这是代码:play.golang.org/p/t7T28IpLNAs
  • 在这里看看:stackoverflow.com/questions/22083490/type-agnostic-channels-进行中
  • 环绕chan interface{}确实有效,但是我希望在源代码中具有显式类型的通道,最好不使用类型转换就使用消息
  • 是什么激发了此代码? 如果您尝试写入一个完整的通道,Go将自动阻止此goroutine,继续执行另一个goroutine,并在可能完成写入时恢复此goroutine。 您无需采取任何手动操作即可"等待时运行另一个线程",这对我来说就像这段代码。
  • @DavidMaze因为通道长度取决于外部数据和使用者,所以我想要一个缓冲的通道以防止阻塞接收

使用反射。 例如,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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")
}

游乐场:https://play.golang.org/p/c5VhIIO0pik

输出:

1
2
3
4
5
6
7
8
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

参考文献:

套餐体现

围棋博客:反思法则

  • 我更喜欢反射而不是类型断言/广播,代码对我来说看起来更干净

创建一个interface{}类型的通道并传递环绕interface{}的任何类型,然后在接收端获取使用类型断言。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 ...
}

Go Playground上的工作代码

编辑:-您也可以将通道包装在interface{}内后,使用反射包来获取通道的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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\
", v.Kind(), v.Len(), v.Cap())
}

func main() {
    ch := make(chan []byte, 100)
    wg.Add(1)
    go monitorChan(ch)
    wg.Wait()
    // actual things below ...
}

游乐场的例子

  • @SnoopyGuo我已经在我编辑过的答案中使用了反射包,以满足您与界面一起使用的要求。