0

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

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

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

在将其降低到仅time.sleep()在一个while循环中之后,对于我为什么应该导致崩溃真的没有意义。我还使用了一个不同的睡眠功能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];
        }
    }
}
4

2 回答 2

3

尝试将您的调用包装到printinpymel.mayautils.executeDeferredmaya.utils.executeDeferred以便它在主 UI 线程上执行。


如果您连续加载并关闭脚本编辑器窗口,您最终应该会收到运行时错误(即 R6025 纯虚函数调用)。这可能需要多次尝试,但似乎总是最终会发生。

我能够在 Maya 2012 上确认这种行为,但我怀疑它是特定于版本的。

我敢打赌,您的测试调用print实际上是导致 Maya 崩溃的原因,因为即使print通常只是一个 python 语句,Maya 也有某种挂钩来更新脚本编辑器的输出窗口(可能还有命令响应栏)使用您正在打印的字符串,它们都在主 UI 线程上运行。

来自Autodesk 知识文章“Python 和线程”

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改为使用。

于 2015-04-01T06:06:44.933 回答
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
于 2019-02-25T02:19:07.067 回答