Майя нить, вызывающая сбой

Я запустил сценарий редактора сценариев автосохранения (с использованием Maya 2014), но он действительно нестабилен и может зависнуть, если что-то произойдет одновременно с сохранением. Я также только что понял, что сбои будут происходить даже без сохранения, поэтому я попытался выяснить, в чем именно заключалась проблема, и в результате остался только какой-то оставшийся код, но все еще способный его воспроизвести.

Моя идея для кода состоит в том, чтобы запустить фоновый поток, где он будет зацикливаться и делать резервные копии сценариев с интервалом, но проверять значение каждую секунду, чтобы убедиться, что он не был приостановлен или отменен (отмененный остановит цикл).

Я предполагаю, что проблема как-то связана с тем, как фоновые потоки работают в Maya, так как это может привести к сбою при загрузке / закрытии окна редактора скриптов или переключении вкладок в настройках представления рендера (по крайней мере, с выбранным Mental Ray, так как кажется, более длительная загрузка вкладок, чем у рендерера по умолчанию). Я предполагаю, что есть и другие способы, но это те, которые действительно было легко найти.

После того, как это просто 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];
        }
    }
}

1 ответ

Решение

Попробуйте перевести ваш звонок на print в pymel.mayautils.executeDeferred или же maya.utils.executeDeferred чтобы он выполнялся в основном потоке пользовательского интерфейса.


если вы постоянно загружаете и закрываете окно редактора сценариев, вы должны в конечном итоге получить ошибку времени выполнения (которая говорит о вызове чисто виртуальной функции R6025). Это может занять несколько попыток, но всегда кажется, что в конечном итоге это произойдет.

Мне удалось подтвердить это поведение на Maya 2012, и я сомневаюсь, что это зависит от версии.

Держу пари, что ваш тестовый звонок print это то, что на самом деле заставляет Майю падать, потому что даже если print обычно это просто выражение на python, Maya имеет своего рода зацепку для обновления окна вывода редактора сценариев (и, возможно, панели командного отклика) печатаемой строкой, которые работают в основном потоке пользовательского интерфейса.

Из статьи Autodesk Knowledge "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 вместо.

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
Другие вопросы по тегам