如何在Go中向多个频道发送消息

huangapple go评论76阅读模式
英文:

How to send message to multiple channels in go

问题

我的翻译如下:

所以我的问题是如何向通道发送消息,只有在通道未关闭且仅发送一次时,broadcast函数才会接收到消息。

发送消息后,应该增加sentNumber

我只是提醒一下,发送消息到所有通道是有时间限制的!

package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	sentNumber int
)

func broadcast(waitTime time.Duration, message string, ch ...chan string) (sentNumber int) {
	start := time.Now()
	for _, channel := range ch {
		if time.Since(start) >= waitTime {
			break
		}
		go send(channel, message)
	}
	return 0
}

func send(channel chan string, message string) {
	for {
		if _, open := <-channel; open {
			break
		}
	}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		wg.Done()
		channel <- message
	}()
	wg.Wait()
}

func main() {
	a := make(chan string, 1)
	b := make(chan string, 1)
	broadcast(5, "秘密消息", a, b)
	fmt.Println(<-a)
	fmt.Println(<-b)
}

希望对你有帮助!

英文:

so my question is how to send message to channels that broadcast function gets only if channel is not closed and just for once.

after sending message should increase sentNumber.

I say just to remind, there is a time limit for sending message to all channels!

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

var (
	sentNumber int
)

func broadcast(waitTime time.Duration, message string, ch ...chan string) (sentNumber int) {
	start := time.Now()
	for _, channel := range ch {
		if time.Since(start) &gt;= waitTime {
			break
		}
		go send(channel, message)
	}
	return 0
}

func send(channel chan string, message string) {
	for {
		if _,open := &lt;-channel; open{
			break
		}
	}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		wg.Done()
		channel &lt;- message
	}()
	wg.Wait()
}

func main() {
	a := make(chan string, 1)
	b := make(chan string, 1)
	broadcast(5, &quot;secret message&quot;, a, b)
	fmt.Println(&lt;-a)
	fmt.Println(&lt;-b)
}

答案1

得分: 1

  1. time.Since(start) >= waitTime 无法中断 send 函数。
  2. 在这种情况下,go send(channel, message) 不应该比单线程队列更高效。
  3. broadcast 不负责检查通道是否已关闭,通道的创建/关闭不是由 broadcast 完成。
package main

import (
	"context"
	"fmt"
	"time"
)

func broadcast(waitTime time.Duration, message string, chs ...chan string) (sentNumber int) {
	ctx, cancel := context.WithTimeout(context.Background(), waitTime)
	defer cancel()

	jobQueue := make(chan chan string, len(chs))
	for _, c := range chs {
		jobQueue <- c
	}

queue:
	for c := range jobQueue {
		select {
		case c <- message:
			// 发送成功
			sentNumber += 1
			if sentNumber == len(chs) {
				cancel()
			}
		case <-ctx.Done():
			// 超时,中断任务队列
			break queue
		default:
			// 如果发送失败,稍后重试
			jobQueue <- c
		}
	}

	return
}

func main() {
	a := make(chan string)
	b := make(chan string)

	go func() {
		time.Sleep(time.Second)
		fmt.Println("a:", <-a)
	}()

	go func() {
		time.Sleep(3 * time.Second)
		fmt.Println("b:", <-b)
	}()

	c := broadcast(2*time.Second, "secret message", a, b)
	fmt.Printf("发送数量:%d\n", c)

	time.Sleep(3 * time.Second)
}
英文:
  1. time.Since(start) &gt;= waitTime can't break the send function
  2. go send(channel, message) should not be more efficient than a single thread queue in this case
  3. broadcast has no responsibility to check if channel has been closed, channels were not created/closed by broadcast
package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

func broadcast(waitTime time.Duration, message string, chs ...chan string) (sentNumber int) {
	ctx, cancel := context.WithTimeout(context.Background(), waitTime)
	defer cancel()

	jobQueue := make(chan chan string, len(chs))
	for _, c := range chs {
		jobQueue &lt;- c
	}

queue:
	for c := range jobQueue {
		select {
		case c &lt;- message:
            // sent success
			sentNumber += 1
			if sentNumber == len(chs) {
				cancel()
			}
		case &lt;-ctx.Done():
            // timeout, break job queue
			break queue
		default:
            // if send failed, retry later
			jobQueue &lt;- c
		}
	}

	return
}

func main() {
	a := make(chan string)
	b := make(chan string)

	go func() {
		time.Sleep(time.Second)
		fmt.Println(&quot;a:&quot;, &lt;-a)
	}()

	go func() {
		time.Sleep(3 * time.Second)
		fmt.Println(&quot;b:&quot;, &lt;-b)
	}()

	c := broadcast(2*time.Second, &quot;secret message&quot;, a, b)
	fmt.Printf(&quot;sent count:%d\n&quot;, c)

	time.Sleep(3 * time.Second)
}

huangapple
  • 本文由 发表于 2021年10月15日 07:34:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/69578436.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定