- Overview
- Features
- Installation
- Quick Start
- API Reference
- Performance
- Use Cases
- About This Company
- Contributing
- License
A high-performance concurrent JSON unmarshalling library for Go that processes slices of byte data using worker pools.
fanunmarshal is designed for scenarios where you need to unmarshal large amounts of JSON data efficiently. It uses a configurable worker pool pattern to process [][]byte data concurrently, providing significant performance improvements over sequential processing.
Perfect for:
- Processing Redis MGet responses
- Bulk JSON data processing
- High-throughput API response handling
- Large dataset transformations
- π High Performance: 2-3x faster than sequential JSON unmarshalling
- βοΈ Configurable Worker Pools: Set optimal worker count for your workload
- π¦ Flexible Input: Process
[][]byteslices or channels - π§ JSON Library Choice: Use stdlib
jsonor high-performancejsoniter - π Auto-scaling: Automatically adjust workers based on data size
- πΎ Memory Efficient: Minimal memory overhead with worker pool pattern
go get github.com/thisisdevelopment/fanunmarshalpackage main
import (
"fmt"
"github.com/thisisdevelopment/fanunmarshal"
)
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
// Your JSON data as [][]byte (e.g., from Redis MGet)
jsonData := [][]byte{
[]byte(`{"id":"1","name":"Alice","age":25}`),
[]byte(`{"id":"2","name":"Bob","age":30}`),
[]byte(`{"id":"3","name":"Charlie","age":35}`),
}
// Configure and process
var expected User
results := fanunmarshal.New().
WithWorkers(10). // Use 10 concurrent workers
WithUseJsonIter(). // Use jsoniter for better performance
UnMarshalSlice(jsonData, &expected)
// Process results
for _, result := range results {
user := result.(*User)
fmt.Printf("User: %+v\n", user)
}
}func processWithChannel() {
jsonData := [][]byte{
[]byte(`{"id":"1","name":"Alice","age":25}`),
[]byte(`{"id":"2","name":"Bob","age":30}`),
}
var expected User
fm := fanunmarshal.New().
WithWorkers(5).
WithUseJsonIter().
DisableAutoScaleDown()
// Create input channel
inputChan := fm.MakeChan(jsonData)
// Process via channel
outputChan := fm.UnMarshalChan(inputChan, &expected, nil)
// Consume results
for result := range outputChan {
user := result.(*User)
fmt.Printf("User: %+v\n", user)
}
}// Main interface
type IFanUnMarshal interface {
WithWorkers(workers uint) IFanUnMarshal
DisableAutoScaleDown() IFanUnMarshal
WithUseJsonIter() IFanUnMarshal
UnMarshalSlice(data [][]byte, expected interface{}) []interface{}
MakeChan(data [][]byte) <-chan []byte
UnMarshalChan(pipe <-chan []byte, expected interface{}, dataLength *int) <-chan interface{}
}WithWorkers(n uint): Set number of concurrent workers (default: 2)WithUseJsonIter(): Use jsoniter instead of stdlib json for better performanceDisableAutoScaleDown(): Prevent automatic worker count adjustment based on data size
UnMarshalSlice(data [][]byte, expected interface{}) []interface{}: Process slice synchronouslyUnMarshalChan(pipe <-chan []byte, expected interface{}, dataLength *int) <-chan interface{}: Process channel asynchronouslyMakeChan(data [][]byte) <-chan []byte: Convert slice to channel
- Result Order: Results may not maintain the original input order due to concurrent processing
- Error Handling: Panics on JSON unmarshal errors (consider wrapping in recover)
- Memory Usage: Each worker creates a deep copy of the expected struct
- Auto-scaling: With channels, provide
dataLengthor disable auto-scaling
Benchmarks on 1000 JSON objects (~1.4MB total):
| Method | Time per Operation | Performance Gain |
|---|---|---|
| Sequential stdlib | ~8.35ms | baseline |
| fanunmarshal + stdlib (10 workers) | ~3.57ms | 2.3x faster |
| fanunmarshal + jsoniter (10 workers) | ~2.57ms | 3.2x faster |
# Run benchmarks
go test -bench=. -benchtime=1sDetailed Benchmark Results
Sequential Processing (stdlib json)
BenchmarkPlainUnMarshal-4 141 8334686 ns/op
fanunmarshal + stdlib json (10 workers)
BenchmarkWithLibSlice_stdlib_10-4 336 3573922 ns/op
fanunmarshal + jsoniter (10 workers)
BenchmarkWithLibSlice_jsoniter_10-4 501 2469929 ns/op
- Redis MGet responses: Perfect for processing multiple cached JSON objects
- Bulk API processing: Transform large datasets from external APIs
- Log processing: Parse multiple JSON log entries concurrently
- Data migration: Convert large JSON datasets efficiently
- Microservice communication: Process batched JSON responses
- Small datasets (< 100 items)
- Single JSON objects
- Memory-constrained environments
- Applications requiring strict result ordering
This is a digital agency located in Utrecht, Netherlands, specializing in crafting high-performance, resilient, and scalable digital solutions, APIs, microservices, and more. Our multidisciplinary team of designers, developers, and strategists collaborate to deliver innovative technology and exceptional user experiences.
Contributions are welcome! Please check out CONTRIBUTING.md for guidelines on how to help improve fanunmarshal.
Β© This is Development BV, 2022~time.Now() Released under the MIT License