【问题标题】:Monitor chan T fullness in golang在golang中监控chan T丰满度
【发布时间】:2018-12-16 06:58:12
【问题描述】:

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

func monitorChan(ch chan T) {
    for {
        if len(ch) == cap(ch) {
            log.Warn("log")
        }
        time.Sleep(chanMonitorInterval)
    }
}

显示错误:

不能在参数中使用 ch (type chan []byte) 作为 type chan interface {} 监控Chan。

这个函数如何修改为每个通道都写一次监控?


这是我的代码:

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
  • 环绕chan interface{} 确实有效,但我希望通道在源代码中具有显式类型,最好在不进行类型转换的情况下使用消息
  • 这段代码的动机是什么?如果您尝试写入一个完整的通道,Go 将自动阻止这个 goroutine,恢复另一个,并在可能完成写入时恢复这个 goroutine。您不需要采取任何手动操作来“在您等待时允许另一个线程运行”,这就是这段代码对我的感觉。

标签: generics go


【解决方案1】:

使用反射。例如,

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

输出:

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

参考资料:

Package reflect

The Go Blog: The Laws of Reflection

【讨论】:

  • 我更喜欢反射而不是类型断言/强制转换,代码对我来说看起来更干净
【解决方案2】:

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

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{}987654326@

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 ...
}

Playground example

【讨论】:

  • @SnoopyGuo 我在我编辑的答案中使用了反射包,以满足您与界面一起使用的要求。
猜你喜欢
  • 2015-08-31
  • 2013-09-13
  • 2018-05-11
  • 1970-01-01
  • 2018-07-03
  • 2015-03-17
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多