在Golang中,当等待命令执行完成时,从通道中收集数据。

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

collect data from channel while waiting for command to complete its execution in golang

问题

我正在启动一个命令执行,触发一个服务,该服务会在一个通道(resChan)上发送结果。现在我需要收集在命令执行期间在这个通道上接收到的结果,但我不知道有多少数据对象会到达resChan。

  1. //启动命令
  2. cmd.start()
  3. //如果知道resChan的长度,可以正常工作,否则会一直等待resChan
  4. for {
  5. result <- resChan
  6. //对结果进行一些操作
  7. }
  8. //等待命令执行完成
  9. cmd.wait()
  10. return result;

另外,resChan没有被关闭,唯一停止数据收集的方法是当命令执行停止时。

英文:

I am starting and a command execution which triggers a service which sends results on a channel (resChan), now i have to collect the results that i receive on this channel while command is executing, i don't have the len of how much data objects will arrive on resChan.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

  1. //start command
  2. cmd.start()
  3. //here if length of resChan is known it works else it keeps waiting for resChan
  4. for {
  5. result &lt;- resChan
  6. //do some operation on result
  7. }
  8. //wait for command
  9. cmd.wait()
  10. return result;

<!-- end snippet -->

Also the resChan is not closed, there is only way to stop data collection that is when command execution stops.

答案1

得分: 1

如果我理解正确,你可以同时监听结果并将其收集以供以后使用,类似于(Playground):

  1. func main() {
  2. cmd := &command{
  3. ResChan: make(chan int),
  4. done: make(chan struct{}),
  5. }
  6. collector := &collector{
  7. // 我们使用命令的通道来获取值
  8. ch: cmd.ResChan,
  9. done: make(chan struct{}),
  10. }
  11. collector.collect()
  12. cmd.start()
  13. cmd.wait()
  14. collector.stop()
  15. fmt.Println(collector.Results)
  16. }
  17. type collector struct {
  18. ch chan int
  19. Results []int
  20. done chan struct{}
  21. }
  22. func (c *collector) collect() {
  23. go func() {
  24. for {
  25. // select 语句将阻塞,直到其中任一通道接收到值
  26. // 它每次只执行一个 case(顺序执行)
  27. // 这就是为什么我们不需要锁定切片来修改它
  28. select {
  29. case v := <-c.ch:
  30. c.Results = append(c.Results, v)
  31. case <-c.done:
  32. return
  33. }
  34. }
  35. }()
  36. }
  37. func (c *collector) stop() {
  38. // 向通道发送信号以停止结果的收集
  39. c.done <- struct{}{}
  40. }
  41. type command struct {
  42. ResChan chan int
  43. done chan struct{}
  44. }
  45. func (c *command) start() {
  46. go func() {
  47. // 命令获取结果并将其发送到通道,供用户使用
  48. for i := 0; i < 10; i++ {
  49. c.ResChan <- i
  50. }
  51. // 其他执行过程完成后,我们发送信号给等待命令
  52. time.Sleep(time.Second)
  53. c.done <- struct{}{}
  54. }()
  55. }
  56. func (c *command) wait() {
  57. // 阻塞,直到有东西发送到 done 通道
  58. <-c.done
  59. }

collector.collect()cmd.start()并发执行并通过 ResChan 通道进行值的传递。你不需要知道结果的长度。

英文:

If I understood correctly you could listen to the results concurrently and collect them for later use, something like (Playground):

  1. func main() {
  2. cmd := &amp;command{
  3. ResChan: make(chan int),
  4. done: make(chan struct{}),
  5. }
  6. collector := &amp;collector{
  7. // We use the command&#39;s channel to get the values
  8. ch: cmd.ResChan,
  9. done: make(chan struct{}),
  10. }
  11. collector.collect()
  12. cmd.start()
  13. cmd.wait()
  14. collector.stop()
  15. fmt.Println(collector.Results)
  16. }
  17. type collector struct {
  18. ch chan int
  19. Results []int
  20. done chan struct{}
  21. }
  22. func (c *collector) collect() {
  23. go func() {
  24. for {
  25. // The select will block until either of the channels receives a value
  26. // it will always execute one case at the time (sequential execution).
  27. // That&#39;s why we don&#39;t need to lock the slice to modify it
  28. select {
  29. case v := &lt;-c.ch:
  30. c.Results = append(c.Results, v)
  31. case &lt;-c.done:
  32. return
  33. }
  34. }
  35. }()
  36. }
  37. func (c *collector) stop() {
  38. // Send a signal into the channel to stop the collection of results
  39. c.done &lt;- struct{}{}
  40. }
  41. type command struct {
  42. ResChan chan int
  43. done chan struct{}
  44. }
  45. func (c *command) start() {
  46. go func() {
  47. // The command gets the results and sends them
  48. // into the channel to be consumed by the user
  49. for i := 0; i &lt; 10; i++ {
  50. c.ResChan &lt;- i
  51. }
  52. // Other executions take place and once they
  53. // finish we send the signal to the wait command
  54. time.Sleep(time.Second)
  55. c.done &lt;- struct{}{}
  56. }()
  57. }
  58. func (c *command) wait() {
  59. // Blocks until something is sent to the done channel
  60. &lt;-c.done
  61. }

collector.collect() and cmd.start() will be executing concurrently and sharing values by communicating through the ResChan channel. You don't need to know the results length.

答案2

得分: 0

如果你想要通过时间间隔来完成任务,可以像这样做:

  1. type msg struct {
  2. }
  3. func main() {
  4. // 时间间隔:10秒
  5. t := time.NewTicker(time.Duration(5) * time.Second)
  6. ch := make(chan msg)
  7. select {
  8. case <-ch:
  9. // 做你想做的事情
  10. case <-t.C:
  11. // 完成
  12. fmt.Println("通过时间间隔完成")
  13. }
  14. fmt.Println("结束")
  15. }

或者,如果你想要使用另一个通道来关闭:

  1. ch := make(chan msg)
  2. doneCh := make(chan done)
  3. for {
  4. select {
  5. case <-ch:
  6. // 做你想做的事情
  7. case <-doneCh:
  8. // 完成
  9. fmt.Println("通过另一个通道完成")
  10. break
  11. }
  12. }
  13. fmt.Println("结束")

或者这样:

  1. type msg struct {
  2. Done bool
  3. // 和其他你想要的消息
  4. }
  5. ch := make(chan msg)
  6. for {
  7. msg := <-ch
  8. if msg.Done {
  9. break
  10. }
  11. }
  12. fmt.Println("结束")

我的英文不太好,所以我可能会在理解或描述方面有错误:)

英文:

if you want chan can be done by time tick
just like :

  1. type msg struct {
  2. }
  3. func main() {
  4. // time tick : 10s
  5. t := time.NewTicker(time.Duration(5) * time.Second)
  6. ch := make(chan msg)
  7. select {
  8. case &lt;-ch:
  9. // do something you want
  10. case &lt;-t.C:
  11. // done
  12. fmt.Println(&quot; have done by tick&quot;)
  13. }
  14. fmt.Println(&quot;end&quot;)
  15. }

or if you want to have another channel to close

  1. ch := make(chan msg)
  2. doneCh := make(chan done)
  3. for {
  4. select {
  5. case &lt;-ch:
  6. // do something you want
  7. case &lt;-doneCh:
  8. // done
  9. fmt.Println(&quot; have done by another channel&quot;)
  10. break
  11. }
  12. }
  13. fmt.Println(&quot;end&quot;)

or this

  1. type msg struct {
  2. Done bool
  3. // and another msg you want
  4. }
  5. ch := make(chan msg)
  6. for {
  7. msg := &lt;-ch
  8. if msg.Done {
  9. break
  10. }
  11. }
  12. fmt.Println(&quot;end&quot;)

my English is not good, so I may have mistake for understandings or descriptions :)

答案3

得分: -1

请尝试以下代码:

  1. //开始命令
  2. cmd.start()
  3. //如果resChan的长度已知,则可以正常工作;否则,它将一直等待resChan
  4. for {
  5. select {
  6. case result := <-resChan:
  7. //在这里执行你的操作
  8. }
  9. }
  10. //等待命令完成
  11. cmd.wait()
  12. return result;

希望对你有帮助!

英文:

try this

  1. //start command
  2. cmd.start()
  3. //here if length of resChan is known it works else it keeps waiting for resChan
  4. for {
  5. select {
  6. case result :=&lt;- resChan
  7. //your op here
  8. }
  9. }
  10. //wait for command
  11. cmd.wait()
  12. return result;

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

发表评论

匿名网友

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

确定