使用并发编程使多个函数同时工作

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

making multiple functions work at the same time using conccurent programming

问题

我开始学习Go语言中的并发编程,在阅读了一些示例之后,我想尝试创建一个系统,在该系统中,每秒钟都会在终端打印出当前时间,并且用户可以在任何时刻在终端输入任意文本,然后相同的文本将在终端上打印出来(或者我们可以执行其他操作,比如只有在输入特定文本时才打印出来)。基本上,我想用以下形式来编写我的代码:

  • ShowTime:函数,每秒钟打印出时间
  • GetInput:函数,检查用户输入,如果输入不为空,则获取其值并将其传递给另一个函数读取
  • ShowInput:函数,从一个值中读取(如果该值不为空)
  • 如果输入中写入了"done",程序将结束并停止一切操作

目前,我想到了以下解决方案,但在输入后出现错误:
代码:

package main

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

func getInputs(ch chan<- string, wg *sync.WaitGroup) {
	defer wg.Done()

	var input string
	for input != "done" {
		fmt.Scanln(&input)
		if input != "" {
			ch <- input
		}
	}
}

func showInputs(ch <-chan string, wg *sync.WaitGroup) {
	defer wg.Done()

	var msg string

	for msg != "done" {
		msg = <-ch
		if msg == "dog" {
			fmt.Println("YEP thats a dog!")
		}
	}
}

func showTime(ch <-chan string, wg *sync.WaitGroup) {
	defer wg.Done()

	var msg string
	for msg != "done" {
		msg = <-ch
		currentTime := time.Now()
		fmt.Println(currentTime.String())
		time.Sleep(time.Second)
	}
}

func main() {
	var wg sync.WaitGroup
	inChan := make(chan string)

	wg.Add(3)
	go showTime(inChan, &wg)
	go showInputs(inChan, &wg)
	go getInputs(inChan, &wg)

	close(inChan)

	wg.Wait()
	fmt.Println("The End!")
}

错误:

2022-07-07 22:40:10.928195762 +0430 +0430 m=+0.000087833
2022-07-07 22:40:11.928359701 +0430 +0430 m=+1.000251851
2022-07-07 22:40:12.928442575 +0430 +0430 m=+2.000334715
5
panic: send on closed channel
goroutine 8 [running]:
main.getInputs(0x0?, 0x0?)
/mnt/d/GoLang/BlackHat/lab/multifunc/main.go:16 +0xef
created by main.main
/mnt/d/GoLang/BlackHat/lab/multifunc/main.go:53 +0x14d
exit status 2

希望能得到帮助:))

英文:

I started learning about concurrency in Go and after reading some examples i wanted to Try A system in which every second the current time will be printed out in terminal and in every moment user can input any text in terminal and the same text will be printed out in the terminal(or we can do any other stuff like if only a specific text was written that would be printed out). and basically I came up with this form to write my code:

  • ShowTime: function to prints out time every second
  • GetInput: function to check for user input and if the input was not empty get its value and pour it into a variable that another function is going to read
  • ShowInput: function to read from a value and( if the value was not empty )
  • If "done" was written in the inputs the program will end and everything will be stopped

right now i came up with this solution but i get error after putting in an input:
Code:

package main

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

func getInputs(ch chan&lt;- string, wg *sync.WaitGroup) {
	defer wg.Done()

	var input string
	for input != &quot;done&quot; {
		fmt.Scanln(&amp;input)
		if input != &quot;&quot; {
			ch &lt;- input
		}
	}
}

func showInputs(ch &lt;-chan string, wg *sync.WaitGroup) {
	defer wg.Done()

	var msg string

	for msg != &quot;done&quot; {
		msg = &lt;-ch
		if msg == &quot;dog&quot; {
			fmt.Println(&quot;YEP thats a dog!&quot;)
		}
	}
}

func showTime(ch &lt;-chan string, wg *sync.WaitGroup) {
	defer wg.Done()

	var msg string
	for msg != &quot;done&quot; {
		msg = &lt;-ch
		currentTime := time.Now()
		fmt.Println(currentTime.String())
		time.Sleep(time.Second)
	}
}

func main() {
	var wg sync.WaitGroup
	inChan := make(chan string)

	wg.Add(3)
	go showTime(inChan, &amp;wg)
	go showInputs(inChan, &amp;wg)
	go getInputs(inChan, &amp;wg)

	close(inChan)

	wg.Wait()
	fmt.Println(&quot;The End!&quot;)
}

Error:

2022-07-07 22:40:10.928195762 +0430 +0430 m=+0.000087833
2022-07-07 22:40:11.928359701 +0430 +0430 m=+1.000251851
2022-07-07 22:40:12.928442575 +0430 +0430 m=+2.000334715
5
panic: send on closed channel
goroutine 8 [running]:
main.getInputs(0x0?, 0x0?)
/mnt/d/GoLang/BlackHat/lab/multifunc/main.go:16 +0xef
created by main.main
/mnt/d/GoLang/BlackHat/lab/multifunc/main.go:53 +0x14d
exit status 2

Would appreciate the help :))

答案1

得分: 2

问题在于你在 goroutine 开始运行并从中读取/写入数据之后不久(或者甚至在之前,这取决于调度器),就关闭了 inChan

通常情况下,最好的做法是发送 goroutine 在完成任务后关闭通道,或者使用其他协调机制。例如,你的 getInputs 函数可以在接收到 "done" 输入后关闭通道,然后再返回。

你的代码中还存在另一个问题,即 showTime 也从通道接收数据。请注意,这将消耗通道中的一条消息,可能会被其他等待相同消息的 goroutine 错过。可以查阅有关通道的 "fan in, fan out" 模式,了解如何解决这个问题。

英文:

The problem is that you close inChan shortly after (or even before, depending on the scheduler) your goroutines start running and reading/writing from it.

Typically, it would be best if the sending goroutine would close the channel when it's done, or some other coordination mechanism. For example, your getInputs function could close the channel when it gets a "done" input, before returning.

Another issue in your code is that showTime receives from the channel as well. Note that this will consume a message from the channel which can be missed by another goroutine waiting for the same message. Look up channel "fan in, fan out" patterns for how to address this.

huangapple
  • 本文由 发表于 2022年7月8日 02:16:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/72902517.html
匿名

发表评论

匿名网友

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

确定