我已经启动了一个自动保存脚本编辑器脚本(使用Maya 2014),但它确实不稳定,如果在保存的同时发生某些事情,可能会崩溃。我也刚刚意识到即使没有保存也会发生崩溃,所以我试图找出实际问题是什么,最后几乎没有任何代码留下但仍然能够复制它。
我对代码的想法是运行一个后台线程,它会在一定时间内循环和备份脚本,但每秒检查一次值以确保它没有被暂停或取消(取消将停止循环)。
我认为问题与后台线程在Maya中的工作方式有关,因为如果加载/关闭脚本编辑器窗口,或者在渲染视图设置上切换选项卡(至少选择了Mental Ray),它可能会崩溃,因为它似乎比默认渲染器需要更长的加载选项卡)。我认为还有其他方法,但那些方法很容易找到。
在while循环中将其归结为time.sleep()
之后,对我来说,为什么它应该导致崩溃真的没有意义。我还使用了while time.time()>startTime+1
的不同睡眠功能,以确保它不是时间模块,但它仍然导致崩溃。
如果有人想要尝试它,下面是剪切代码,一旦用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];
}
}
}
答案 0 :(得分:3)
尝试将您的呼叫包裹在print
或pymel.mayautils.executeDeferred
中的maya.utils.executeDeferred
,以便在主UI线程上执行。
如果您不断加载并关闭脚本编辑器窗口,最终应该会出现运行时错误(即R6025纯虚函数调用)。它可能需要多次尝试,但似乎最终总会发生。
我能够在Maya 2012上确认这种行为,我怀疑它是特定于版本的。
我敢打赌,你对print
的测试调用实际上是导致Maya崩溃的原因,因为即使print
通常只是一个python语句,Maya也有一些钩子来更新脚本编辑器的输出窗口(可能还有命令响应栏)和您正在打印的字符串,它们都在主UI线程上运行。
来自Autodesk Knowledge article "Python and threading":
Maya API和Maya Command体系结构不是线程安全的。如果在主线程外部调用它们,Maya命令会抛出异常,并且从主线程以外的线程使用OpenMaya API会产生无法预料的副作用。
将print
语句传递给pymel.mayautils.executeDeferred我(至少到目前为止,谁知道Maya ;-))无法导致崩溃。
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
。
答案 1 :(得分:0)
import threading
import time
import maya.utils as utils
run_timer = True
run_num = 0
def example(interval = 10):
global run_timer;global run_num;
def your_function_goes_here():
print "hello",run_num
run_num +=1
while run_timer:
time.sleep(interval)
utils.executeDeferred(your_function_goes_here)
t = threading.Thread(None, target = example, args = (1,) )
t.start()
# stop :
# run_timer = False