PsychoPy textStim Memory Leak Issue

时间:2016-04-15 15:44:35

标签: python psychopy

我一直在开发PsychoPy编码器部分的实验。这是一项相对简单的任务,但需要大量的文本和图像绘制。我几天前试过运行整个实验(包括123次试验),并且在第28次迭代中我收到了以下错误:

WindowsError:exception:写入0x00000004的访问冲突

我调查了这一点,看起来在向窗口绘制大量文本时会出现pyglet中导致的内存泄漏问题。我将我的代码改进为仅在实验需要时更改文本组件。我在下面列出了我的整个代码作为参考:

from __future__ import division
from psychopy import locale_setup, visual, core, event, data, gui
import numpy as np
import pandas as pd
import sys, os, csv, time, random
from win32api import GetSystemMetrics

#Directory:
cwd = os.path.dirname(os.path.abspath(__file__))

#GUI:
expName = "CMNT"
expInfo = {"participant": "", "session": "001", "condition": "F1"}       #Condition Files: F1, F2, M1, or M2
condition = expInfo["condition"]
condition = expInfo["condition"]
dlg = gui.DlgFromDict(dictionary = expInfo, title = expName, order =  ["participant","session","condition"])
if dlg.OK == False:
    core.quit()

#Window:
win = visual.Window(size = (GetSystemMetrics(0), GetSystemMetrics(1)),     fullscr = True, pos = (0,0), units = "norm", color = "Gray")

#Turn off Mouse
event.Mouse(visible = False)

#Timers:
timer = core.Clock()
breakTimer = core.Clock()

#Load Condition File:
stim_df = pd.read_csv("exp_stimuli.csv", nrows = 124)
run_length = 123

#Output Directory:
fileLocation = cwd + "\%s_data\%s" %(expName, expInfo["participant"])
if not os.path.exists(fileLocation):
    os.makedirs(fileLocation)
os.chdir(fileLocation)
if os.path.isfile("logFile.csv"):
    os.remove("logFile.csv")

#List and Panda File Header 
run_param_list = []
header = ["Block","MentalState", "Condition", "Speaker","Prompt",    "RespButton", "CorrAnswer","RT(sec)", "ACC"]

#Define text and image stimuli
text = visual.TextStim(win = win, text = '', height = 0.1, pos = (0,0),    color="White")
image = visual.ImageStim(win = win, pos = (0,0), size = (0.1,0.1), image = cwd + "\\" + "gray.png")

#Run Instruction Page:
text.text = '\t\tREMEMBER:\n\t\tAnswer each question,\n\t\t"Which should I     pick?"\n\t\tusing the LEFT and RIGHT\n\t\tarrow key.'
text.height = 0.1
text.draw()
win.flip()
while True:
    theseKeys = event.getKeys()
    if "escape" in theseKeys:
        core.quit()
    if len(theseKeys):
        break

#Begin Trials:
for i in xrange(run_length):
    if stim_df["MentalState"][i] == "0":
        breakTimer.reset()
        while breakTimer.getTime() < 15.0:
        text.text = "+"
        text.height = 0.25
        text.pos = (0,0)
        text.draw()
    win.flip()
    else:   
        #win.flip()
        timer.reset()
        exit_press = []
        event_press = []

        speaker = visual.TextStim(win, text = stim_df["speaker"][i], height = 0.1, pos = (0,0.6))
        speaker.setAutoDraw(True)

        #0.5 seconds
        while timer.getTime() < 0.5:
            win.flip()   

        #3.0 seconds
        if stim_df["speaker"][i] == "Computer":
            text.text = stim_df["prompt"][i]
            text.pos = (-0.1,0)
            text.height = 0.08
            text_box_length = text.boundingBox[0]/GetSystemMetrics(0)*2

            image.image = cwd + "\\" + "gray.png"
            image.pos = (-0.1,0)
            image.size = (text_box_length, 0.35)

            image.draw()
            text.draw()
        else:
            text.text = stim_df["prompt"][i]
            text.pos = (-0.1,0)
            text.height = 0.08
            text_box_length = text.boundingBox[0]/GetSystemMetrics(0)*2

            image.image = cwd + "\\" + "blue.png"
            image.pos = (-0.1,0)
            image.size = (text_box_length, 0.35)

            image.draw()
            text.draw()

        win.flip()
        while timer.getTime() < 3.5:
            exit_press += event.getKeys()
            if "escape" in exit_press:
                core.quit()            
        onset_Time = timer.getTime()
        speaker.setAutoDraw(False)

        #3.5 seconds
        text.text = stim_df["question"][i]
        text.pos = (0,0.6)
        text.height = 0.1
        text.draw()

        text.text = stim_df["answerA"][i]
        text.pos = (-0.3, -0.5)
        text.draw()

        text.text = stim_df["answerB"][i]
        text.pos = (0.3, -0.5)
        text.height = 0.1
        text.draw()
        win.flip()

        length = 0
        while timer.getTime() < 7.0:
            event_press += event.getKeys(keyList = ["left","right"])
            if len(event_press) > length:
                RT = timer.getTime() - onset_Time
                length = len(event_press)
            elif len(event_press) == 0:
                RT = "N/A"            
            exit_press += event.getKeys()
            if "escape" in exit_press:
                core.quit()

        #Jitter 1 time
        text.text = "+"
        text.pos = (0,0)
        text.height = 0.25
        text.draw()
        win.flip()        
        while timer.getTime() < 7.0 + (stim_df["jitter1"][i]/1000):
            exit_press += event.getKeys()
            if "escape" in exit_press:
                core.quit()
        #Check Conditional Input        
        try:
            response = event_press[-1]
        except:
            response = None

        if response == "left":
            reply = stim_df["answerA"][i]
            if reply == stim_df["corrAnswer"][i]:
                acc = 1
            else:
                acc = 0   
        elif response == "right":
            reply = stim_df["answerB"][i]
            if reply == stim_df["corrAnswer"][i]:
                acc = 1
            else:
                acc = 0
        elif response == None:
            response = "N/A"
            reply = stim_df["corrAnswer"][i]
            acc = 0

        text.text = reply
        text.height = 0.08
        text.pos = (0.1,0.3)
        #2 seconds   
        if stim_df["speaker"][i] == "Computer":     
            text.text = reply
            text.height = 0.08
            text.pos = (0.1,0.3)

            speaker.draw()
            image.image = cwd + "\\" + "gray.png"
            image.size = (text.boundingBox[0]/GetSystemMetrics(0)*2 + 0.2,  text.boundingBox[1]/GetSystemMetrics(1)*2 + 0.1)
            image.pos = (0.1, 0.3)

            image.draw()
            text.draw()

            text.pos = (-0.1,-0.1)
            text.text = reply + u" \u2713"
            text_box_length = text.boundingBox[0]/GetSystemMetrics(0)*2 + 0.1

            image.image = cwd + "\\" + "gray.png"
            image.size = (text.boundingBox[0]/GetSystemMetrics(0)*2 + 0.1, text.boundingBox[1]/GetSystemMetrics(1)*2 + 0.1)
            image.pos = (-0.1,-0.1)

            image.draw()
            text.draw()
        else:
            text.text = reply
            text.height = 0.08
            text.pos = (0.1,0.3)

            speaker.draw()
            image.image = cwd + "\\" + "green.png"
            image.size = (text.boundingBox[0]/GetSystemMetrics(0)*2 + 0.1, text.boundingBox[1]/GetSystemMetrics(1)*2 + 0.1)
            image.pos = (0.1,0.3)

            image.draw()
            text.draw()

            text.text = reply + " :)"
            text.pos = (-0.1,-0.1)

            image.image = cwd + "\\" + "blue.png"
            image.size = (text.boundingBox[0]/GetSystemMetrics(0)*2 + 0.1, text.boundingBox[1]/GetSystemMetrics(1)*2 + 0.1)
            image.pos = (-0.1, -0.1)

            image.draw()
            text.draw()
        win.flip()
        while timer.getTime() < 9.0 + (stim_df["jitter1"][i]/1000):
            exit_press += event.getKeys()
            if "escape" in exit_press:
                core.quit()

        #Jitter 2 time
        text.text = "+"
        text.height = 0.25
        text.pos = (0,0)
        text.draw()
        win.flip()
        while timer.getTime() < 11.0 + (stim_df["jitter1"][i]/1000) + (stim_df["jitter2"][i]/1000):
            exit_press += event.getKeys()
            if "escape" in exit_press:
                core.quit()

        #Panda Output File
        run_param_list.append([stim_df["block"][i], stim_df["MentalState"][i], condition, stim_df["speaker"][i], stim_df["prompt"][i], response, stim_df["corrAnswer"][i], RT, acc])
        fid = pd.DataFrame(run_param_list, columns = header)
        fid.to_csv("logFile.csv", header = True)

#Close up Shop:
win.close()
core.quit()

我想知道是否有人建议如何更好地优化代码,以免发生内存泄漏错误。如果无法修复此错误,最佳解决方案是通过PsychoPy Builder复制实验吗?

1 个答案:

答案 0 :(得分:1)

我的猜测是,这来自pyglet中似乎存在的内存泄漏(这是我们用于文本呈现的内容):  https://bitbucket.org/pyglet/pyglet/issues/66/memory-leak-in-fonttext 听起来像其中一个pyglet开发人员已经找到了解决方案,但是不会包含一段时间。

PsychoPy还有一个名为TextBox的刺激类。这完全是从头开始编写的(由Sol Simpson编写)并且在许多方面更有效,但不能很好地支持字体(具体来说,目前仅支持单倍间距字体)。如果你能够使用它,我相信不会显示相同的内存问题。