2015-04-01 268 views
0

我已经启动了一个自动保存脚本编辑器脚本(使用Maya 2014),但它非常不稳定,并且如果某个事件与保存同时发生,可能会崩溃。我也刚刚意识到即使没有保存时​​也会发生崩溃,所以我试图找出实际问题是什么,最后几乎没有任何代码留下,但仍然能够复制它。Maya线程导致崩溃

我对代码的想法是运行一个后台线程,它会以一定的时间间隔循环和备份脚本,但每秒检查一次值以确保它没有被暂停或取消(取消将会停止循环)。

我认为这个问题与Maya中后台线程的工作方式有关,因为如果加载/关闭脚本编辑器窗口或切换渲染视图设置上的选项卡(至少选择了Mental Ray,它似乎需要比默认渲染器更长的加载选项卡)。我认为还有其他方法,但那些是很容易找到的。

在一个while循环中把它归结为time.sleep()之后,它对我来说真的没有意义,因为它会导致崩溃。我还使用了一个不同的睡眠功能,确保它不是时间模块,但它仍然导致崩溃。

如果有人想尝试它,一旦你开始线程AutoSave.start(),如果你不断加载并关闭脚本编辑器窗口,最终会得到一个运行时错误(表示R6025纯虚函数呼叫)。它可能需要多次尝试,但似乎总是发生。

import threading, time 
import pymel.core as pm 

class AutoSaveThread(object): 
    def __init__(self): 
     thread = threading.Thread(target=self.run, args=()) 
     thread.daemon = True 
     thread.start() 
    def run(self): 
     while True: 
      time.sleep(1) 
      print "Open and close the script editor enough times and this will crash" 

class AutoSave: 
    @classmethod 
    def start(self): 
     AutoSaveThread() 

我有十几个标签打开,以便装载/关闭需要更长的时间比我什么都没有,这可能会增加时间窗口,崩溃可能发生。

为了记录,这里是Maya内置的一小段代码,它将在脚本编辑器窗口关闭时始终运行。我认为这可能与我的修改版本保存有关,然后尝试在同一时间保存,但它仍然在循环中没有任何事情发生。

global proc syncExecuterBackupFiles(){ 
    global string $gCommandExecuter[]; 
    global string $executerBackupFileName; 

    if(`optionVar -q saveActionsScriptEditor`) { 
     // clear the script editor temp dir first before writing temp files 
     string $scriptEditorTempDir = (`internalVar -userPrefDir` + "scriptEditorTemp/"); 
     string $tempFiles[] = `getFileList -folder $scriptEditorTempDir`; 
     string $file; 
     for ($file in $tempFiles) { 
      sysFile -delete ($scriptEditorTempDir + $file); 
     } 

     // save all the executer control text to files 
     int $i = 0; 
     for($i = 0; $i < size($gCommandExecuter); $i++) { 
      cmdScrollFieldExecuter -e -storeContents $executerBackupFileName $gCommandExecuter[$i]; 
     } 
    } 
} 

回答

3

尝试,使其在主UI线程上执行的pymel.mayautils.executeDeferredmaya.utils.executeDeferred你的包裹到print电话。


,如果你不断地加载和关闭脚本编辑器窗口,你应该最终会得到一个运行时错误(也称R6025纯虚函数调用)。它可能需要多次尝试,但似乎总是发生。

我能够在Maya 2012上确认这种行为,我怀疑它是否是特定版本。我的打赌是,你对print的测试调用实际上是导致Maya崩溃的原因,因为即使print通常只是一个python语句,Maya也有一些钩子来更新脚本编辑器的输出窗口(和潜在的命令响应栏)与你正在打印的字符串,它们都在主UI线程上运行。

Autodesk Knowledge article "Python and threading"

玛雅API和Maya指挥架构不是线程安全的。如果在主线程之外调用Maya命令,则会引发异常,并且从主线程以外的线程使用OpenMaya API会产生无法预料的副作用。

通过传递您的print声明pymel.mayautils.executeDeferred我一直无法导致崩溃(至少到目前为止,谁与玛雅知道;-))。

import threading, time 
import pymel.core as pm 

import pymel.mayautils # like maya.utils, for executeDeferred 

# Set to False at any time to allow your threads to stop 
keep_threads_alive = True 

def wrapped_print(): 
    print "Opening and closing the script editor shouldn't make this crash\n" 

class AutoSaveThread(object): 
    def __init__(self): 
     thread = threading.Thread(target=self.run) 
     thread.start() 
    def run(self): 
     while keep_threads_alive: 
      time.sleep(1) 
      pymel.mayautils.executeDeferred(wrapped_print) 

... 

捆绑的唯一副作用特别是一个print说法是,它不再相呼应,命令响应吧。如果保留该行为对您而言很重要,请改为使用pymel.mel.mprint

+0

非常感谢哈哈,我曾试着在'executeDeferred'中包装其他位,但我并不认为这是为了'print'。如果在保存脚本编辑器时加载/关闭脚本编辑器,那么完整的代码仍然会崩溃(怀疑我能做的事情还有很多,但警告人们),但是到目前为止,它似乎还能正常工作。只是好奇,我总是做'maya.utils.executeDeferred',并不知道'pymel.mayautils',是否有优势吗?另外,pymel.mel.mprint'通常比装载pymel的'print'更好用吗? – Peter 2015-04-01 13:06:28

+0

@Peter您应该能够完成这项工作而不必担心崩溃,但这取决于您如何以及何时从脚本编辑器获取数据。 – systemexit 2015-04-01 14:53:20

+1

@Peter'pymel.mayautils.executeDeferred'是'mel.utils.executeDeferred'的一个封装,它也处理Maya在批处理模式下运行的情况,'print'是一个python语句,而'mprint'调用'maya .mel.eval'使用mel的打印。我链接的pymel文档解释了两者的差异,并且更好,两者的来源都可以访问。请参阅Maya安装中的“Python/lib/site-packages/pymel/mayautils.py”和“Python/lib/site-packages/pymel/core/language.py”。 – systemexit 2015-04-01 15:06:55