psychopy.org | Reference | Downloads | Github

Screen Stucks When Using core.wait Function

When delaying the stimulus through core.wait function, the screen would stop responding for a second if the time inside core.wait function is too long.

from psychopy import visual, core
win = visual.Window(fullscr = False, size = (800,600),color = (-1.0,-1.0,-1.0), units = 'norm', monitor = 'testMonitor')
Shape = visual.ShapeStim(win, lineColor = None, 
                    fillColor = 'grey', 
                    opacity =1.0, 
                    vertices = [[0.2,0.05],[-0.2,0.05],[-0.2,-0.05],[0.2,-0.05]], 
                    pos = (0,0))
Shape.draw()
win.flip()
core.wait(10)

I am currently testing it on on window 10 64 bit , Python 3.7.4, Psychopy 3.2.3

This sounds like what core.wait() is intended to do. Can you try explaining the problem in more detail?

If the secs parameter inside core.wait function is too long, the window that displays the stimulus would literally stop responding like a stucked program, with the cursor turned into a spinning blue circle.

I believe this is an issue where events like mouse clicks or the window manager events are not getting handled. The simple (and “bad” from a CPU activity perspective) solution would be to specify:

core.checkPygletDuringWait = True
core.wait(10,hogCPUperiod=10)

A “better” solution would be to modify your clock.py code so that it deals with events during the less precise timing period. One suggestion is below, but make sure you check the timing precision as it matters for your purposes. On my machine both codes time the 1-2 s time period with error <.1 ms

Replace the current def wait() code in clock.py with

def _hogCPUactivity():
    """Helper function for :func:`~.psychopy.core.wait
       
       Handles window event if needed or returns otherwise.
    """
    
    from . import core
    
    if not (core.havePyglet and core.checkPygletDuringWait):
        return
    # let's see if pyglet collected any event in meantime
    try:
        # this takes focus away from command line terminal window:
        if parse_version(pyglet.version) < parse_version('1.2'):
            # events for sounds/video should run independently of wait()
            pyglet.media.dispatch_events()
    except AttributeError:
        # see http://www.pyglet.org/doc/api/pyglet.media-module.html#dispatch_events
        # Deprecated: Since pyglet 1.1, Player objects schedule themselves
        # on the default clock automatically. Applications should not call
        # pyglet.media.dispatch_events().
        pass
    for winWeakRef in core.openWindows:
        win = winWeakRef()
        if (win.winType == "pyglet" and
                hasattr(win.winHandle, "dispatch_events")):
            win.winHandle.dispatch_events()  # pump events
            
def wait(secs, hogCPUperiod=0.2):
    """Wait for a given time period.

    If secs=10 and hogCPU=0.2 then for 9.8s python's time.sleep function
    will be used, which is not especially precise, but allows the cpu to
    perform housekeeping. In the final hogCPUperiod the more precise
    method of constantly polling the clock is used for greater precision.

    If you want to obtain key-presses during the wait, be sure to use
    pyglet and to hogCPU for the entire time, and then call
    :func:`psychopy.event.getKeys()` after calling
    :func:`~.psychopy.core.wait()`

    If you want to suppress checking for pyglet events during the wait,
    do this once::

        core.checkPygletDuringWait = False

    and from then on you can do::

        core.wait(sec)

    This will preserve terminal-window focus during command line usage.
    """
    t0 = getTime()

    # initial relaxed period, using sleep (better for system resources etc)
    if secs > hogCPUperiod:
        tenths = int((secs-hogCPUperiod)*10)
        leftover = secs - tenths*.0998 - hogCPUperiod
        for tenths in range(int((secs-hogCPUperiod)*10)):
            time.sleep(.0998)
            _hogCPUactivity()
        time.sleep(leftover)

    # hog the cpu, checking time
    while (getTime() - t0) < secs:
        _hogCPUactivity()