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.
//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;
Also the resChan is not closed, there is only way to stop data collection that is when command execution stops.
CodePudding user response:
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.
CodePudding user response:
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 :)
CodePudding user response:
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;