With viztask, you can pause the execution of a function while waiting for some condition, like a few seconds to pass, without blocking the Vizard main loop or spawning an operating system thread.
The viztask module and viz.director functions have similar functionality; however, there are important differences. Calling viz.director actually creates a new thread, while scheduling a task does not. This means that calling a long blocking operation in a task will block the Vizard update loop as well and the frame rate will go to zero. However, in most cases, tasks should be used because they are much more CPU/memory efficient and are non-preemptive so synchronization locks are not necessary.
Any function that is passed to the scheduler must have a yield statement within it. This line tells the program to stop until a condition has been met. There are a number of predefined conditions that tasks can wait for. Check out the yield conditions in the Tasks command table for a list. In the following example, <viztask>.addAction adds the fading action to the ball and waits for that action to be completed before moving to the next line in the scheduled function.
To run a task repeatedly, just use standard loop statement (while or for). If you want to stop a looping task, kill it with <viztask:Task>.kill.
Many viztask yield statements return a viz.Data object with data about the event or condition that occurred (e.g. <viztask>.waitMouseDown returns information about the mouse button that was pressed and the time it was pressed.) The <viztask>.waitEvent command will wait for any standard or custom event and return data about that event. Check out the Event reference for standard events or the Custom events section for more on making your own kind of event.
Here's an example with <viztask>.waitKeyDown that waits for a keypress and then uses the returned key to proceed.
If you want to create a custom condition for your yield statement, write a viztask.Condition class. The update function within this class will generally be called once per frame. When it returns True, the scheduler will continue. In the following example, the up-arrow key moves the ball upwards until it reaches one meter, and then repositions it at zero. Here, waitHigh is the custom condition. It returns True when the object reaches the specified height. The scheduled function then proceeds.
You can embed sub tasks within a scheduled task. For example, doTrial is scheduled within executeExperiment. The parent task waits for the sub task to finish before it continues.
When called inside a task function, the viztask.returnValue command will set a return value and stop the task. The return value is available to the parent task that yielded the sub-task.
Task functions are implemented using Python generators, which don't allow return values. This command works around this limitation by raising a special exception that stores the return value. The viztask module will handle this exception and return the value to the parent task.
Note: Since this command raises an exception to return the value, you should not call this command within a try/except block
Signal objects are useful for communicating between tasks. Tasks can either wait for, or send, signals. In the following example, one ball waits for the signal to change color while the other ball sends out the signal between actions.