当前位置: 首页 > 面试题库 >

当涉及多个渠道时,选择如何工作?

陈夜洛
2023-03-14
问题内容

我在多个非缓冲通道上使用select时发现

select {
case <- chana:
case <- chanb:
}

即使两个通道都具有数据,但是在处理此选择时,在chana和case chanb中落下的调用也不平衡。

package main

import (
    "fmt"
    _ "net/http/pprof"
    "sync"
    "time"
)

func main() {
    chana := make(chan int)
    chanb := make(chan int)

    go func() {
        for i := 0; i < 1000; i++ {
            chana <- 100 * i
        }
    }()

    go func() {
        for i := 0; i < 1000; i++ {
            chanb <- i
        }
    }()

    time.Sleep(time.Microsecond * 300)

    acount := 0
    bcount := 0
    wg := sync.WaitGroup{}
    wg.Add(1)
    go func() {
        for {
            select {
            case <-chana:
                acount++
            case <-chanb:
                bcount++
            }
            if acount == 1000 || bcount == 1000 {
                fmt.Println("finish one acount, bcount", acount, bcount)
                break
            }
        }
        wg.Done()
    }()

    wg.Wait()
}

运行此演示,当其中一个通道完成读/写操作时,另一个通道可能仍保留999-1。

有什么方法可以确保平衡?


问题答案:

Go
select语句不偏向任何(就绪)情况。引用规范:

如果可以进行一种或多种通信,则可以通过 统一的伪随机选择 来选择可以进行的单个通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,则“
select”语句将阻塞,直到可以进行至少一种通信为止。

如果可以进行多次通信,则随机选择一个。这不是一个完美的随机分布,并且规范不能保证这一点,但是它是随机的。

您所体验到的是Go
Playground具有GOMAXPROCS=1(可以在此处验证)和goroutine调度程序没有抢占性的结果。这意味着默认情况下,goroutine不会并行执行。如果遇到阻塞操作(例如,从网络读取或试图从阻塞的通道接收或在其上发送),则将goroutine置于停顿状态,然后继续运行。

而且,由于您的代码中没有阻塞操作,因此goroutines可能不会停放,可能只有您的一个“生产者” goroutines会运行,而另一个可能无法调度。

在本地计算机上运行您的代码GOMAXPROCS=4,我得到的结果非常“真实”。运行几次,输出:

finish one acount, bcount 1000 901
finish one acount, bcount 1000 335
finish one acount, bcount 1000 872
finish one acount, bcount 427 1000

如果需要确定单个案例的优先级,请查看以下答案:强制执行goselect语句的优先级

的默认行为select不能保证优先级相等,但是平均而言它将接近它。如果您需要保证相等的优先级,则不应使用select,但是您可以从2个通道中进行2个非阻塞接收的序列,如下所示:

for {
    select {
    case <-chana:
        acount++
    default:
    }
    select {
    case <-chanb:
        bcount++
    default:
    }
    if acount == 1000 || bcount == 1000 {
        fmt.Println("finish one acount, bcount", acount, bcount)
        break
    }
}

如果两个电源值均相等,则上述2个非阻塞接收将以相等的速度(具有相同的优先级)消耗2个通道,如果一个不相同,则不断接收来自另一个的信号而不会延迟或阻塞。

需要注意的一件事是,如果 没有_一个通道提供任何要接收的值,则这基本上是一个“忙”循环,因此会消耗计算能力。为避免这种情况,我们可能检测到没有通道准备就绪,_然后select对两个接收都使用一条语句,然后将阻塞该语句,直到其中一个接收准备就绪,而不会浪费任何CPU资源:

for {
    received := 0
    select {
    case <-chana:
        acount++
        received++
    default:
    }
    select {
    case <-chanb:
        bcount++
        received++
    default:
    }

    if received == 0 {
        select {
        case <-chana:
            acount++
        case <-chanb:
            bcount++
        }
    }

    if acount == 1000 || bcount == 1000 {
        fmt.Println("finish one acount, bcount", acount, bcount)
        break
    }
}


 类似资料:
  • 本文向大家介绍Android多渠道打包时获取当前渠道的方法,包括了Android多渠道打包时获取当前渠道的方法的使用技巧和注意事项,需要的朋友参考一下 作为Android app,发布多个分发平台是常规操作。然后,有时由于个渠道面对的用户不同,或平台审核标准不同,需要在各渠道使用不同的业务逻辑,这就需要根据渠道使用选择差异化代码。 这里把简单的代码记一下。 首先,分渠道打包很简单。 在项目的bui

  • 问题内容: 当存在内部类时,我很难理解继承在Java中的工作方式。我目前正在处理一些子类需要稍微更改其父类的内部类功能的事情。我在下面提出了一个更简单,类似的示例。 我希望此代码可以打印“我是ChildClass.InnerClass”,但可以打印“我是ParentClass.InnerClass”。为什么是这样?另外,如果我将main中的obj对象更改为ChildClass类型,则输出将更改为“

  • 问题内容: 我们正在构建一个电子商务应用程序。我们正在将JAVA堆栈与Hibernate和Spring框架一起使用。与所有电子商务应用程序一样,我们需要在我们的电子商务应用程序中构建搜索功能。 因此,我们遇到了Hibernate Search 和Apache Solr 。有人可以列出两者的优缺点,以便我们为Enterprise Search选择理想的解决方案吗? 问题答案: Apache Solr

  • 问题内容: 如何选择多个文件? 问题答案: 新答案: 在HTML5中,您可以添加属性以选择多个文件。 旧答案: 每个只能选择1个文件。如果要发送多个文件,则必须使用多个输入标签或使用Flash或Silverlight。

  • 问题内容: 我需要格式化类似于下面的HTML。基本上,引号是 可选的 ,我需要删除正文段落的首字母。 我的CSS看起来像这样: 引入报价后,该功能目前不起作用。AFAIK我无法选择不是“ quote”类的文章的第一个子项P。如果无法弄清楚,我将使用jQuery,但现在我正在寻找一种仅使用CSS的方法。 提前致谢! 问题答案: 如果可以使用CSS3选择器,请尝试使用这些选择器(组合在一起): 否则,