Neon
← Back to Handling errorsNext: Modules →

Parallel Programming

Neon supports concurrent programming via processes (lightweight threads). Since Neon runs on platforms without true multitasking (like TI-EZ80), it simulates concurrency by interleaving processes.


1. The parallel Operator

Launch a function in a new process using parallel.

Syntax

promise = parallel functionName(arg1, arg2, ...)

Key Points

Example

function slowTask(n) do
    # Simulate a slow computation
    total = 0
    for (i, 0, n) do
        total += i
    end
    return (total)
end

# Launch two tasks in parallel
promise1 = parallel slowTask(1000)
promise2 = parallel slowTask(2000)

# At this point, both tasks are running in the background
# The promises are of type "Promise"

# Wait for results (passive waiting)
await(promise1 != None and promise2 != None)

# Now the promises have resolved to their return values
print(promise1)  # → 499500 (sum of 0..999)
print(promise2)  # → 1999000 (sum of 0..1999)

2. Promises

Example: Chaining Promises

function double(x) do
    return (x * 2)
end

p1 = parallel double(5)  # Promise
p2 = p1                  # Another reference to the same Promise

await(p1 != None)
print(p1)  # → 10
print(p2)  # → 10 (also updated)

3. Passive Waiting with await

Example: Passive Waiting

function worker(id) do
    print("Worker " + str(id) + " started")
    # Simulate work
    for (i, 0, 100000) do
        pass
    end
    print("Worker " + str(id) + " finished")
    return (id * 10)
end

# Launch workers
p1 = parallel worker(1)
p2 = parallel worker(2)

# Passively wait for both to finish
await(p1 != None and p2 != None)

print("Both workers done!")
print("Results: " + str(p1) + ", " + str(p2))

4. Process-Local Variables

Example

counter = 0

function incrementCounter() do
    local(counter)  # Makes counter local to this process
    counter += 1
    print("Counter in process: " + str(counter))
end

# Launch 3 processes
parallel incrementCounter()
parallel incrementCounter()
parallel incrementCounter()

# Wait for all to finish
await(True)  # Simple way to yield (not ideal, but works here)

# Global counter remains unchanged
print("Global counter: " + str(counter))  # → 0

5. Atomic Blocks

Prevent race conditions by making a block of code atomic (uninterruptible).

Syntax

atomic
    # Code that must run without interruption
end

Example:

Not thread-safe function:

function consumer(data) do
  while (len(data) > 0) do
    # Here, data[0] is possibly no longer accessible since another thread could have consumed this item
    consume(data[0])
    data.remove(0)
  end
end

thread-safe function using atomic blocks:

function consumer(data) do
  while (len(data) > 0) do
    atomic
      if (len(data) > 0) then
        item = data[0]
        data.remove(0)
      end
    end
    consume(item)
  end
end

6. Controlling Process Switching

Example

setAtomicTime(100)  # Switch processes every 100 yield calls

← Back to Handling errorsNext: Modules →