-
Notifications
You must be signed in to change notification settings - Fork 0
Async Dashboard Approaches
Comprehensive Guide: Understanding the async implementations in randomwalk
Related Pages:
- How Async Dashboard Uses Crew and Targets - Detailed crew patterns
- Dynamic Grid Broadcasting Algorithm - Technical deep dive
- Overview
- Approach 1: Synchronous (workers=0)
- Approach 2: Crew-Only Async (Static Snapshots)
- Approach 3: Chunked Mode (RECOMMENDED)
- Approach 4: Nanonext Broadcasting (DEPRECATED)
- Comparison Table
- Choosing the Right Approach
- Examples
The randomwalk package provides multiple execution modes for simulation:
| Mode | workers |
sync_mode |
Grid Updates | Use Case |
|---|---|---|---|---|
| Synchronous | 0 | n/a | After each walker | WebR/Shinylive, baseline |
| Static Async | 1+ | "static" | None during sim | Production, simplicity |
| Chunked | 1+ | "chunked" | Between batches | RECOMMENDED |
| Dynamic | 1+ | "dynamic" | N/A |
All walkers execute sequentially in the main R process. Each walker sees the grid updated by all previous walkers.
result <- randomwalk::run_simulation(
grid_size = 100,
n_walkers = 50,
workers = 0 # Synchronous mode
)- WebR/Shinylive compatible: Yes - runs entirely in browser
- Grid updates: Real-time (each walker sees previous paths)
- Performance: Sequential, but no overhead
- Use case: Browser dashboards, baseline comparisons
Each worker receives a static copy of the grid at simulation start. Workers execute independently without communication:
Main Process
├─ Create empty grid
├─ Start crew controller
├─ Push walker tasks (each with grid snapshot)
│
│ Worker 1: [Grid copy] → Walker 1 → Walker 3 → Walker 5
│ Worker 2: [Grid copy] → Walker 2 → Walker 4 → Walker 6
│
├─ Wait for all workers
├─ Collect results
├─ Aggregate walker paths onto final grid
└─ Return combined result
result <- randomwalk::run_simulation(
grid_size = 100,
n_walkers = 50,
workers = 4, # Use 4 crew workers
sync_mode = "static" # Default: static grid snapshots
)They don't - each walker operates on the initial grid state:
# Walker 1 starts at (50, 50), creates path...
# Walker 2 starts at (30, 30), also uses ORIGINAL grid
# Walker 2 does NOT see Walker 1's path during simulation
# Paths are merged AFTER all walkers complete- Simple mental model
- No synchronization overhead
- Reproducible results
- Works with any crew backend
- Walkers cannot react to each other's paths
- Grid state is "stale" during execution
- Not WebR compatible (crew requires multiple processes)
Processes walkers in batches of 10, with grid synchronization between batches:
Batch 1: Walkers 1-10 execute in parallel
↓ Grid updated with all new black pixels
Batch 2: Walkers 11-20 execute (see batch 1 results)
↓ Grid updated
Batch 3: ...
result <- randomwalk::run_simulation(
grid_size = 100,
n_walkers = 50,
workers = 4,
sync_mode = "chunked" # RECOMMENDED
)- ~3x more black pixels than static mode (walkers see previous batches)
- Better collision detection
- No socket complexity
- Good balance of parallelism and interaction
The chunked mode provides a good balance:
- Walkers in later batches see earlier batches' paths
- No complex socket management
- Works reliably (no deprecated dependencies)
⚠️ DEPRECATED: Bothsync_mode = "dynamic"andsync_mode = "mirai_dynamic"are deprecated because nanonext sockets fail in crew/mirai subprocesses. Use"chunked"instead.
Workers would communicate black pixel updates in near real-time using nanonext publish/subscribe sockets.
# From R/simulation.R:
if (sync_mode %in% c("dynamic", "mirai_dynamic")) {
logger::log_warn("sync_mode is DEPRECATED: nanonext sockets fail in crew/mirai subprocesses")
logger::log_warn("Use sync_mode='chunked' for ~3x more black pixels (RECOMMENDED)")
}Technical reason: nanonext socket handles cannot be passed to crew/mirai subprocess contexts. The sockets become invalid in child processes.
When it worked, the message count was:
- O(N) where N = walkers that create black pixels
- NOT "10-20 messages" as previously documented
- Each walker broadcasts at most ONCE (when it terminates adjacent to a black pixel)
| Aspect | Sync (workers=0) | Static | Chunked | Dynamic |
|---|---|---|---|---|
| Status | ✅ Active | ✅ Active | ✅ RECOMMENDED | |
| WebR compatible | ✅ Yes | ❌ No | ❌ No | ❌ No |
| Walker interaction | Full | None | Between batches | N/A |
| Black pixels | Baseline | Few | ~3x more | N/A |
| Overhead | None | Minimal | Minimal | N/A |
| Dependencies | None | crew | crew | crew + nanonext |
Running in WebR/Shinylive?
│
├─ Yes → Use workers=0 (sync) - ONLY option
│
└─ No → Need parallel processing?
│
├─ No → Use workers=0 (sync)
│
└─ Yes → Do walkers need to see each other?
│
├─ No → Use sync_mode="static"
│
└─ Yes → Use sync_mode="chunked" (RECOMMENDED)
| Scenario | Recommended |
|---|---|
| Browser dashboard (WebR/Shinylive) | workers = 0 |
| Production batch processing | workers = 4, sync_mode = "static" |
| Interactive exploration | workers = 4, sync_mode = "chunked" |
| Maximum walker interaction |
workers = 0 (sync sees all updates) |
# Sync mode - works in browser
result <- randomwalk::run_simulation(
grid_size = 100,
n_walkers = 50,
workers = 0 # Required for WebR
)# Static async - fast, predictable
result <- randomwalk::run_simulation(
grid_size = 100,
n_walkers = 100,
workers = 4,
sync_mode = "static"
)# Chunked mode - best balance
result <- randomwalk::run_simulation(
grid_size = 200,
n_walkers = 50,
workers = 4,
sync_mode = "chunked" # Walkers see previous batches
)- How Async Dashboard Uses Crew and Targets - Deep dive into crew patterns
- Dynamic Grid Broadcasting Algorithm - Technical details (for reference)
- crew package: https://wlandau.github.io/crew/
- targets package: https://docs.ropensci.org/targets/
-
randomwalk source:
R/simulation.R