Concurrent Batch (Headless)
Headless (no GUI) example demonstrating parallel batch execution with core.EvalBatch. Uses only the core package — no Fyne/GUI dependencies.
Features
- Compile once, run many - A single script is compiled to bytecode once, then run over many inputs concurrently
- Isolated VMs - Each input runs on its own
Context+VM with no shared mutable state - Bounded concurrency -
BatchConfig{Concurrency: 4}caps how many inputs run at once - Index-aligned results - Output order matches input order; per-input errors are reported individually
- Per-input globals - Each input map is exposed to the script as global variables
Worker Script
worker.risor is the unit of work — it reads the CSV file named by the per-input global file, sums the amount column, and returns a summary map:
require(["v0.8", "@csv"])
// `file` is supplied per-input by core.EvalBatch — one run per CSV file,
// each on its own isolated VM.
let rows = csv.read(file)
let total = 0
rows.each(row => { total = total + int(row["amount"]) })
// The final expression is this run's result (returned to Go as map[string]any).
{
"rows": len(rows),
"total": total,
}Go Host
// One input per file; each becomes the global `file` for that run.
inputs := make([]map[string]any, len(files))
for i, f := range files {
inputs[i] = map[string]any{"file": f}
}
results, err := core.EvalBatch(
context.Background(),
string(script),
inputs,
core.BatchConfig{Concurrency: 4},
core.WithCSV(),
)
// Results are index-aligned with inputs. Per-input failures appear in r.Err;
// the returned error is only for setup/compile failures.
for i, r := range results {
if r.Err != nil {
fmt.Printf("%-16s ERROR: %v\n", files[i], r.Err)
continue
}
fmt.Printf("%-16s %v\n", files[i], r.Value)
}ℹ️
EvalBatch is headless only — do not use it to drive Fyne widgets. Stateless modules like csv/json/strings are safe across workers; values shared via WithGlobal must be made concurrency-safe by the caller.Running
cd examples/40-concurrent-batch
go run main.goExpected output (order-stable, one line per file):
data/east.csv map[rows:4 total:400]
data/north.csv map[rows:3 total:425]
data/south.csv map[rows:2 total:625]
data/west.csv map[rows:2 total:355]