TDAsyncIO
Overview
Section titled “Overview”TouchDesigner typically runs Python scripts synchronously on its main thread. If a script takes a long time to execute (e.g., waiting for a network request, performing heavy computation, or handling file I/O), it blocks the main thread, causing the entire TouchDesigner interface and process to freeze.
Python’s asyncio
library provides a way to write asynchronous code using async
and await
, allowing long-running tasks to run concurrently without blocking. However, integrating asyncio
’s event loop directly into TouchDesigner’s frame-based execution requires careful management.
TDAsyncIO
solves this problem by providing a managed asyncio
event loop that runs incrementally within the TouchDesigner frame cycle. It allows you to launch asynchronous tasks (coroutines) and monitor their progress without freezing your project.
Within LOPs, TDAsyncIO
is a crucial utility, often embedded within other components (like ChatTD
) to handle operations like API calls that would otherwise block the main thread.
Key Concepts
Section titled “Key Concepts”- Event Loop:
TDAsyncIO
manages anasyncio
event loop. In each TouchDesigner frame where the component cooks, it runs one iteration of the event loop, allowing scheduled tasks to advance. - Tasks: You submit asynchronous functions (coroutines defined with
async def
) to the manager using theRun
method. Each submission becomes a tracked task. - Task Lifecycle: Tasks progress through statuses:
pending
->running
->completed
/failed
/cancelled
/timeout
. - Task Table: An internal Table DAT (
task_table
) provides visibility into all managed tasks, showing their ID, status, description, duration, start/end times, and any errors.
The primary way to use TDAsyncIO
is via its Python extension, typically accessed through an operator reference.
Python Example:
import asyncio
# Get a reference to the TDAsyncIO componenttd_asyncio_op = op('path/to/TDAsyncIO') # Adjust path as needed
# Define an asynchronous function (coroutine)async def wait_and_print(duration, message): print(f"Task started: Waiting for {duration} seconds...") await asyncio.sleep(duration) # Non-blocking wait print(f"Task finished: {message}") return f"Completed after {duration} seconds"
# --- Running a single task ---print("Submitting single task...")task_id_1 = td_asyncio_op.ext.AsyncIOManager.Run( coroutines=wait_and_print(3, "Hello from async task 1!"), description="Simple Wait Task", info={'custom_data': 'value1'}, timeout=10 # Optional: Cancel if not done in 10 seconds)print(f"Submitted task with ID: {task_id_1}")
# --- Running multiple tasks ---print("Submitting multiple tasks...")task_id_list = td_asyncio_op.ext.AsyncIOManager.Run( coroutines=[ wait_and_print(2, "Task 2 finished!"), wait_and_print(4, "Task 3 finished!") ], description="Batch Wait Tasks" # Shared description)# Note: Run returns the ID of the *last* task submitted in the listprint(f"Submitted batch, last task ID: {task_id_list}")
# --- Getting a result (example) ---# Note: You would typically check task status or use callbacks# This is just a basic example, results are available after completion# result = td_asyncio_op.ext.AsyncIOManager.GetTaskResult(task_id_1)# if result:# print(f"Result for task {task_id_1}: {result}")
Key Points:
- Use
async def
to define your asynchronous functions. - Use
await
insideasync def
functions for operations that would normally block (liketime.sleep
, network requests with libraries likeaiohttp
, etc.). Useasyncio.sleep()
for non-blocking delays. - Pass the coroutine object (the result of calling your
async def
function) to theRun
method. - The
Run
method takes the following arguments:coroutines
: A single coroutine or a list/tuple of coroutines.description
(Optional[str]): A description shown in the task table.info
(Optional[dict]): Additional metadata stored with the task and shown in the table.timeout
(Optional[float]): Time in seconds after which the task will be automatically cancelled if still running.
Parameters
Section titled “Parameters”op('tdasyncio').par.Clearafter
Float - Default:
600
op('tdasyncio').par.Cancelactive
Pulse - Default:
None
op('tdasyncio').par.Clearall
Pulse - Default:
None
op('tdasyncio').par.Clearfinished
Pulse - Default:
None
Task Table DAT
Section titled “Task Table DAT”Inside the TDAsyncIO
component, there is a Table DAT named task_table
which displays the status of all managed asynchronous tasks. Key columns include:
task_id
: Unique identifier for the task.status
: Current state (pending, running, completed, failed, cancelled, timeout).description
: The description provided when the task was run.duration
: Time elapsed since the task started (for running tasks) or total execution time (for finished tasks).created_at
,completed_at
: Timestamps for task start and end.error
: Error message if the task failed.info
: Additional metadata provided when the task was run.
This table is useful for monitoring the progress and outcome of your asynchronous operations.
Related Operators
Section titled “Related Operators”- ChatTD - Integrates TDAsyncIO internally to handle asynchronous LLM API calls.