Doing things in parallel
Coroutines run multiple items in parallel—or, to be more exact, they run items in rapid alternation in a way that looks parallel. Not all items support coroutines.
Using coroutines
You can use coroutines through the coroutines plugin (see Figure 1).
As you can see, the coroutines plugin looks similar to the sequence item, but has a few extra options:
- Duration indicates the total duration of the coroutines.
- End after item (optional) indicates that the coroutines should end when a specific item has ended. This allows you, for example, to indicate that the coroutines should end when a key press has been collected, by selecting a keyboard_response item here.
- Each item has a Start time. Most items also have an End time. The end time does not apply to one-shot items; for example, sketchpads show a display and terminate immediately, so they have no end time.
Specifically, the example from Figure 1 (from the stop-signal-task example) does the following:
- It shows a target display immediately.
- If the
stop_after
variable is not empty, it shows the stop_signal display after an interval specified by thestop_after
variable. - During the entire (2000 ms) interval, a keyboard response is collected.
The temporal flow is controlled by the coroutines plugin. Therefore, the timeout and duration values specified in the items are not used. For example, in Figure 1, the keyboard_response will run for 2000 ms, regardless of the timeout that is specified in the item.
Supported items
Currently, the following items are supported (this list may not be exhaustive):
- feedback
- inline_script
- keyboard_response
- logger
- mouse_response
- sampler
- synth
- sketchpad
Using inline_script items in coroutines
When you use an inline_script item in a coroutines, the Run phase works a little differently from what you might be used to. Specifically, the Run phase is executed on every iteration of the coroutines. In addition, the Run phase should only contain code that takes very little time to execute; this is because time-consuming operations will block the coroutines, thus interfering with the timing of other items in the coroutines as well. To end the coroutines, you can raise an AbortCoroutines()
exception.
For example, say that you have a coroutines with two keyboard_response items, kb1 and kb2, and you want to run the coroutines until two key presses have been collected, with a timeout of 5000 ms. You could then create the following coroutines structure:
The check_responses inline_script would then first set both responses variables to an empty string in the Prepare phase:
# This is executed at the start of the coroutines
response_kb1 = ''
response_kb2 = ''
And then, in the Run phase, check if both variables have been set, and abort the coroutines if this is the case:
# Values that are not an empty string are True for Python
# This code will be executed many times!
if response_kb1 and response_kb2:
raise AbortCoroutines()
Run-if expressions
The behavior of run-if expressions in coroutines is a bit different from that in sequence items. Specifically, run-if expressions in coroutines are evaluated during the prepare phase. See also: