Your problem requires a concurrent processing and then a sequential read. @helmbert's solution is simple and elegant enough to solve your problem with a bit more tweak.
However, you can also perform a controlled concurrent execution and then a sequential read using the below procedure. It is not very clean but I have used something like this before and it works fine. (Please note that the code below almost certainly has bugs, so be careful).
objs := []*MyStruct{}
// concurrency factor. This controlls the number of
// goroutines you'll be running. (note that number of goroutines
// can be cf+1 also if len(serializeds) % cf != 0.
cf := 3
// length of sub slice each goroutine will be procesing
subSliceLen := len(serializeds) / cf // cf must be > len
// make a channel to get error from goroutines
errorCh := make(chan error)
// chans will store the created channels in proper order
chans := make([]chan *MyStruct)
// quit channel to signal currently executing goroutines to stop
quit := make([]chan struct{})
// loop to only read a part of the original input slice
for i := 0; i <= len(serializeds); i += subSliceLen {
// setup slice sub section to be processed. may be bugged!!
hi := subSliceLen
if i + hi >= len(serializeds) {
hi = len(serializeds)
}
// create a channel for the goroutine that will handle
// input slice values from i to hi. It is important to make
// these channels buffered otherwise there will be no possibility
// of parallel execution.
ch := make(chan *MyStruct{}, subSliceLen)
chans = append(chans, ch)
go func(ch chan *MyStruct, i, hi int) {
defer close(ch)
for _, s := range serialzed[i:hi] {
deserializedObject, ok, err := doDeserialization(s)
if err != nil {
// if any err, abandon the whole thing
errorCh <- err
// signal other goroutines that they should
// stop the work and return
close(quit)
return
}
if !ok {
continue
}
select {
// this is required in order to receive the signal that
// some other goroutine has encountered an error and that
// this goroutine should also cleanly return. without this
// there will be a goroutine leak.
case <- quit:
return
case ch <- deserializedObject:
// do nothing
}
}
}(ch, i, hi)
}
Now chans
has all the channels that are now receiving the processed data. We can now start reading sequentially from them.
i := 0
for {
select {
case v, ok := <-chans[i]:
if !ok {
// chans[i] is closed and has been read completely
if i >= len(chans) {
break
}
// proceed to the next channel
i++
}
objs = append(objs, v)
case <- err:
// handle error, close all
}
}