Parallel Computations

Powerful Parallel Computing with BoxLang's Async Framework

Introduced in v1.4.0

BoxLang's async framework provides powerful tools for parallel computing, allowing you to execute multiple operations concurrently and efficiently process large datasets. Whether you're processing arrays, transforming data structures, or running independent computations, BoxLang's parallel computing BIFs give you the tools to maximize performance while maintaining code simplicity.

Sequential:  Task1 → Task2 → Task3 → Task4  (16 seconds)
             🟦    🟦    🟦    🟦

Parallel:    Task1 ↘
             Task2  → Results              (4 seconds)
             Task3 ↗
             Task4 ↙
             🟦🟦🟦🟦

🎯 Core Parallel Computing BIFs

BoxLang provides several Built-In Functions (BIFs) for parallel computing:

BIF
Purpose
Input
Output

asyncAll()

Execute futures in parallel

Array of futures/functions

BoxFuture

asyncAny()

Race multiple futures

Array of futures/functions

BoxFuture

asyncRun()

Execute single function async

Function

BoxFuture

asyncAllApply()

Apply function to collection in parallel

Array/Struct + mapper

Array/Struct

futureNew()

Create new BoxFuture

Value/Function

BoxFuture

🚀 Basic Parallel Execution

asyncAll() - Execute All in Parallel

The asyncAll() BIF executes multiple operations concurrently and returns results in order:

Advanced Example with Mixed Types:

asyncAny() - Race to the Finish

The asyncAny() BIF returns the result of the first operation to complete:

Timeout and Fallback Pattern:

🔄 Data Processing with asyncAllApply()

The asyncAllApply() BIF is perfect for applying transformations to collections in parallel:

Array Processing

Struct Processing

With Error Handling

With Custom Executor and Timeout

🔢 Collection Parallel Methods

BoxLang provides powerful parallel processing capabilities for all collection types (arrays, lists, queries, and structs) through parallel versions of common iteration methods. These methods can dramatically improve performance when processing large collections or when the callback functions involve expensive operations.

Just make sure you understand the intricacies of creating and managing parallel tasks, as improper use can lead to resource contention or inefficient execution.

📋 Supported Collection Types

All parallel methods work across these data types:

Type
Methods

Array

arrayEach(), arrayEvery(), arrayFilter(), arrayMap(), arrayNone(), arraySome()

List

listEach(), listEvery(), listFilter(), listMap(), listNone(), listSome()

Query

queryEach(), queryEvery(), queryFilter(), queryMap(), queryNone(), querySome()

Struct

structEach(), structEvery(), structFilter(), structMap(), structNone(), structSome()

🎯 Collection Method Purposes

Each collection method serves a specific purpose in data processing:

Method
Purpose
Input
Output
Use Case

Each

Iteration with side effects

Collection + callback

void

Logging, notifications, updating external state

Every

Universal validation

Collection + predicate

boolean

Check if ALL items meet the criteria predicate

Filter

Selective extraction

Collection + predicate

New collection

Extract items matching conditions

Map

Transformation

Collection + mapper

New collection

Transform each item to new form

None

Negative validation

Collection + predicate

boolean

Ensure NO items meet the criteria predicate

Some

Existence check

Collection + predicate

boolean

Check if ANY items meet the criteria predicate

🔄 Each - Perform Actions

Execute side effects for each item without returning results:

Every - Validate All

Test whether ALL items in a collection meet a condition:

🔍 Filter - Extract Matching Items

Create a new collection containing only items that meet criteria:

🔄 Map - Transform Items

Transform each item into a new form, creating a new collection:

None - Ensure Absence

Verify that NO items in the collection meet a condition:

🔎 Some - Check Existence

Test whether AT LEAST ONE item meets a condition:

🎛️ Parallel Execution Parameters

All collection parallel methods support these consistent parameters:

Execution Modes:

  • parallel: false - Sequential execution (default)

  • parallel: true, maxThreads: null - Uses common ForkJoinPool (automatic thread count)

  • parallel: true, maxThreads: N - Creates custom ForkJoinPool with N threads

  • parallel: true, virtual: true - Uses virtual threads for unlimited concurrency

  • parallel: true, maxThreads: true - Shorthand for virtual threads (positional syntax)

🔄 Array Parallel Processing

📝 List Parallel Processing

List methods include additional delimiter parameters before parallel options:

🗄️ Query Parallel Processing

🏗️ Struct Parallel Processing

🎯 Method-Specific Examples

Each - Side Effects

Every - Validation

Some - Existence Check

None - Negative Validation

⚡ Performance Benefits

🌟 Virtual Threads: The Game Changer

Introduced in BoxLang v1.5.0

Virtual threads are lightweight, managed by the JVM, and perfect for I/O-intensive operations. Unlike platform threads, you can create millions of virtual threads without performance degradation.

🎯 When to Use Virtual Threads

✅ Perfect for Virtual Threads:

  • Network I/O: API calls, database queries, file downloads

  • File Operations: Reading/writing many files

  • External Service Calls: Microservice communication

  • Blocking Operations: Any operation that waits

❌ Better with Platform Threads:

  • CPU-Intensive Work: Mathematical calculations, data processing

  • Memory-Intensive Operations: Large object manipulation

  • Short-Running Tasks: Operations that complete quickly

🔄 Virtual Thread Examples

Network I/O Operations

Database Operations

File Processing

🆚 Virtual vs Platform Threads Comparison

Aspect
Platform Threads
Virtual Threads

Max Concurrent

~1,000-5,000

Millions+

Memory per Thread

~2MB stack

~Few KB

Creation Cost

Expensive

Cheap

Best For

CPU-intensive

I/O-intensive

JVM Management

OS-scheduled

JVM-managed

Blocking Behavior

Blocks OS thread

Suspends virtually

📊 Performance Comparison

🎛️ Best Practices for Collection Parallel Processing

1. Choose Appropriate Thread Count

2. Use Parallel Processing for Right-Sized Collections

3. Expensive Operations Benefit Most

⚡ Single Async Operations

asyncRun() - Basic Async Execution

With Custom Executor:

futureNew() - Creating Futures

🎛️ Advanced Patterns

Pipeline Processing

Fan-Out/Fan-In Pattern

Retry with Exponential Backoff

🛠️ Executor Management

Using Custom Executors

🚨 Thread Cancellation Control

For scenarios where you need to cancel all running threads, use a custom executor that you can shutdown:

⚠️ Important Notes on Cancellation:

  • Thread cancellation is cooperative - tasks must check for interruption

  • Use Thread.interrupted() or Thread.currentThread().isInterrupted() in your code

  • Not all operations can be cancelled (e.g., blocking I/O)

  • Cancellation may not be immediate

📊 Performance Monitoring

Timing Parallel Operations

Memory and Resource Monitoring

🎯 Best Practices

✅ Do's

  1. Choose the Right Tool:

  2. Choose the Right Threading Model:

  3. Handle Errors Gracefully:

  4. Use Appropriate Executors:

❌ Don'ts

  1. Don't Block in Parallel Code:

  2. Don't Use Virtual Threads for CPU-Intensive Work:

  3. Don't Create Too Many Platform Threads:

  4. Don't Forget Resource Cleanup:

📈 Performance Comparison


With BoxLang's parallel computing capabilities, you can dramatically improve application performance by leveraging multiple CPU cores and concurrent execution. Choose the right BIF for your use case, handle errors properly, and always consider resource management for optimal results.

Last updated

Was this helpful?