英文:
collect data from channel while waiting for command to complete its execution in golang
问题
我正在启动一个命令执行,触发一个服务,该服务会在一个通道(resChan)上发送结果。现在我需要收集在命令执行期间在这个通道上接收到的结果,但我不知道有多少数据对象会到达resChan。
//启动命令
cmd.start()
//如果知道resChan的长度,可以正常工作,否则会一直等待resChan
for {
  result <- resChan
  //对结果进行一些操作
}
//等待命令执行完成
cmd.wait()
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 -->
//start command
cmd.start()
//here if length of resChan is known it works else it keeps waiting for resChan
for {
  result <- resChan
  //do some operation on result
}
//wait for command
cmd.wait()
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):
func main() {
	cmd := &command{
		ResChan: make(chan int),
		done:    make(chan struct{}),
	}
	collector := &collector{
        // 我们使用命令的通道来获取值
		ch:   cmd.ResChan,
		done: make(chan struct{}),
	}
	collector.collect()
	cmd.start()
	cmd.wait()
	collector.stop()
	fmt.Println(collector.Results)
}
type collector struct {
	ch      chan int
	Results []int
	done    chan struct{}
}
func (c *collector) collect() {
	go func() {
		for {
			// select 语句将阻塞,直到其中任一通道接收到值
			// 它每次只执行一个 case(顺序执行)
			// 这就是为什么我们不需要锁定切片来修改它
			select {
			case v := <-c.ch:
				c.Results = append(c.Results, v)
			case <-c.done:
				return
			}
		}
	}()
}
func (c *collector) stop() {
	// 向通道发送信号以停止结果的收集
	c.done <- struct{}{}
}
type command struct {
	ResChan chan int
	done    chan struct{}
}
func (c *command) start() {
	go func() {
		// 命令获取结果并将其发送到通道,供用户使用
		for i := 0; i < 10; i++ {
			c.ResChan <- i
		}
		// 其他执行过程完成后,我们发送信号给等待命令
		time.Sleep(time.Second)
		c.done <- struct{}{}
	}()
}
func (c *command) wait() {
	// 阻塞,直到有东西发送到 done 通道
	<-c.done
}
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):
func main() {
	cmd := &command{
		ResChan: make(chan int),
		done:    make(chan struct{}),
	}
	collector := &collector{
        // We use the command's channel to get the values
		ch:   cmd.ResChan,
		done: make(chan struct{}),
	}
	collector.collect()
	cmd.start()
	cmd.wait()
	collector.stop()
	fmt.Println(collector.Results)
}
type collector struct {
	ch      chan int
	Results []int
	done    chan struct{}
}
func (c *collector) collect() {
	go func() {
		for {
			// The select will block until either of the channels receives a value
			// it will always execute one case at the time (sequential execution).
			// That's why we don't need to lock the slice to modify it
			select {
			case v := <-c.ch:
				c.Results = append(c.Results, v)
			case <-c.done:
				return
			}
		}
	}()
}
func (c *collector) stop() {
	// Send a signal into the channel to stop the collection of results
	c.done <- struct{}{}
}
type command struct {
	ResChan chan int
	done    chan struct{}
}
func (c *command) start() {
	go func() {
		// The command gets the results and sends them 
        // into the channel to be consumed by the user
		for i := 0; i < 10; i++ {
			c.ResChan <- i
		}
		// Other executions take place and once they 
        // finish we send the signal to the wait command
		time.Sleep(time.Second)
		c.done <- struct{}{}
	}()
}
func (c *command) wait() {
	// Blocks until something is sent to the done channel
	<-c.done
}
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
如果你想要通过时间间隔来完成任务,可以像这样做:
type msg struct {
}
func main() {
	// 时间间隔:10秒
	t := time.NewTicker(time.Duration(5) * time.Second)
	ch := make(chan msg)
	select {
	case <-ch:
		// 做你想做的事情
	case <-t.C:
		// 完成
		fmt.Println("通过时间间隔完成")
	}
	fmt.Println("结束")
}
或者,如果你想要使用另一个通道来关闭:
ch := make(chan msg)
doneCh := make(chan done)
for {
	select {
	case <-ch:
		// 做你想做的事情
	case <-doneCh:
		// 完成
		fmt.Println("通过另一个通道完成")
		break
	}
}
fmt.Println("结束")
或者这样:
type msg struct {
	Done bool
	// 和其他你想要的消息
}
ch := make(chan msg)
for {
	msg := <-ch
	if msg.Done {
		break
	}
}
fmt.Println("结束")
我的英文不太好,所以我可能会在理解或描述方面有错误:)
英文:
if you want chan can be done by time tick
just like :
type msg struct {
}
func main() {
	// time tick : 10s
	t := time.NewTicker(time.Duration(5) * time.Second)
	ch := make(chan msg)
	select {
	case <-ch:
		// do something you want
	case <-t.C:
		// done
		fmt.Println(" have done by tick")
	}
	fmt.Println("end")
}
or if you want to have another channel to close
	ch := make(chan msg)
	doneCh := make(chan done)
	for {
		select {
		case <-ch:
			// do something you want
		case <-doneCh:
			// done
			fmt.Println(" have done by another channel")
			break
		}
	}
	fmt.Println("end")
or this
type msg struct {
	Done bool
	// and another msg you want
}
	ch := make(chan msg)
	for {
		msg := <-ch
		if msg.Done {
			break
		}
	}
	fmt.Println("end")
my English is not good, so I may have mistake for understandings or descriptions :)
答案3
得分: -1
请尝试以下代码:
	//开始命令
	cmd.start()
	//如果resChan的长度已知,则可以正常工作;否则,它将一直等待resChan
	for {
		select {
			case result := <-resChan:
				//在这里执行你的操作
		}
	}
	//等待命令完成
	cmd.wait()
	return result;
希望对你有帮助!
英文:
try this
	//start command
cmd.start()
//here if length of resChan is known it works else it keeps waiting for resChan
for {
select {
case result :=<- resChan
//your op here
}
}
//wait for command
cmd.wait()
return result;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论