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:
TDAsyncIOmanages anasyncioevent 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 theRunmethod. 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 defto define your asynchronous functions. - Use
awaitinsideasync deffunctions 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 deffunction) to theRunmethod. - The
Runmethod 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.