No decoder goroutines (test)
diff --git a/zstd/decoder.go b/zstd/decoder.go
index f593e46..185f98d 100644
--- a/zstd/decoder.go
+++ b/zstd/decoder.go
@@ -97,10 +97,12 @@
 
 	// Create decoders
 	d.decoders = make(chan *blockDec, d.o.concurrent)
-	for i := 0; i < d.o.concurrent; i++ {
-		dec := newBlockDec(d.o.lowMem)
-		dec.localFrame = newFrameDec(d.o)
-		d.decoders <- dec
+	if d.o.async {
+		for i := 0; i < d.o.concurrent; i++ {
+			dec := newBlockDec(d.o.lowMem)
+			dec.localFrame = newFrameDec(d.o)
+			d.decoders <- dec
+		}
 	}
 
 	if r == nil {
@@ -202,6 +204,14 @@
 		return nil
 	}
 
+	if !d.o.async {
+		for i := 0; i < d.o.concurrent; i++ {
+			dec := newBlockDec(d.o.lowMem)
+			dec.localFrame = newFrameDec(d.o)
+			d.decoders <- dec
+		}
+	}
+
 	// Remove current block.
 	d.current.decodeOutput = decodeOutput{}
 	d.current.err = nil
@@ -249,6 +259,28 @@
 			return
 		}
 	}
+
+	// Drain...
+	if !d.o.async {
+		if d.stream != nil {
+			close(d.stream)
+		}
+		for i := 0; i < d.o.concurrent; i++ {
+			select {
+			case dec := <-d.decoders:
+				dec.Close()
+			default:
+			}
+		}
+		if d.stream != nil {
+			d.streamWg.Wait()
+			d.stream = nil
+		}
+		if d.current.d != nil {
+			d.current.d.Close()
+			d.current.d = nil
+		}
+	}
 }
 
 // WriteTo writes data to w until there's no more data to write or when an error occurs.
diff --git a/zstd/decoder_options.go b/zstd/decoder_options.go
index c0fd058..156b1bd 100644
--- a/zstd/decoder_options.go
+++ b/zstd/decoder_options.go
@@ -15,6 +15,7 @@
 // options retains accumulated state of multiple options.
 type decoderOptions struct {
 	lowMem         bool
+	async          bool
 	concurrent     int
 	maxDecodedSize uint64
 	dicts          []dict
@@ -25,10 +26,18 @@
 		// use less ram: true for now, but may change.
 		lowMem:     true,
 		concurrent: runtime.GOMAXPROCS(0),
+		async:      true,
 	}
 	o.maxDecodedSize = 1 << 63
 }
 
+func (o *decoderOptions) finalize() error {
+	if o.lowMem && o.concurrent == 1 {
+		o.async = false
+	}
+	return nil
+}
+
 // WithDecoderLowmem will set whether to use a lower amount of memory,
 // but possibly have to allocate more while running.
 func WithDecoderLowmem(b bool) DOption {