Concurrency and execution

Concurrency and execution

A normal call executes in the current flow and may wait for capture, processing, gestures, UI dispatch, or user input. parallel on a touch and Flow.start are different mechanisms. Blocking describes a wait in the calling flow, not a freeze of the Android UI.

Background flows

Flow.start(name, params=None) starts an isolated branch and returns its Int ordinal. There are at most two background branches per Run. No Flow.stop(), pause(), resume(), join(), or handle API exists. Main completion waits for the background branches; any branch error and System.stop() stop the whole Run.

# Configure a macro flow named watch_enemy before running
ordinal = Flow.start("watch_enemy", {"task": "status"})
print(ordinal)

Shared state

Use separate mutable values/builders in each flow. Storage is deliberately shared and locks individual operations, including tracked nested edits. Storage.get() followed by Storage.set() is not atomic; use one writer for read-modify-write work. Screen capture/cache controls are also shared; changing them affects every branch.

Queued touches

parallel=True queues a touch; outside collect mode delay_before and delay_after still wait in the caller. Touch.collect() gathers touches for Touch.send(), and Touch.wait() waits for completion. Gestures share Android’s input channel; they do not become independent devices. Cancellation of active gestures requires Android 8 or newer.

# Collect overlapping touches, then wait for completion
Touch.collect()
click((300, 900), hold_ms=1500, parallel=True)
click((780, 900), delay_before=500, parallel=True)
Touch.send()
Touch.wait()

Recognition and UI waits

Region.find* searches for appearance; Region.wait* waits for disappearance. Even one-pass recognition takes processing time. Polling rate is limited to 1–60 Hz. Interactive MacroPanel prompts serialize and wait for the user. OverlayText is owned by its flow; off_all() only releases overlays from that flow, while UI work goes through Android Main.