Потоки Maya вызывают сбой

Я запустил скрипт редактора скриптов автосохранения (используя 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];
        }
    }
}

person Peter    schedule 01.04.2015    source источник


Ответы (2)


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


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

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

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

Из Статья 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.

person systemexit    schedule 01.04.2015
comment
Большое спасибо, ха-ха, я пытался обернуть другие биты в executeDeferred, но я не подумал сделать это для print. Полный код по-прежнему будет аварийно завершать работу при загрузке/закрытии редактора сценариев во время его сохранения (сомневаюсь, что я могу что-то с этим сделать, но предупреждаю людей), но пока что в остальном он работает нормально. Просто любопытно, я всегда делал maya.utils.executeDeferred и не знал о pymel.mayautils, есть ли преимущество одного над другим? Кроме того, лучше ли использовать pymel.mel.mprint, чем print, если загружен pymel? - person Peter; 01.04.2015
comment
@Peter Вы должны иметь возможность выполнять эту работу, не беспокоясь о сбоях, но это зависит от того, как и когда вы получаете данные из редактора сценариев. - person systemexit; 01.04.2015
comment
@Peter pymel.mayautils.executeDeferred — это оболочка для mel.utils.executeDeferred, которая также обрабатывает, когда Maya запускается в пакетном режиме, а print — это оператор Python, тогда как mprint вызывает maya.mel.eval для использования печати Мела. Документы pymel, на которые я ссылался, довольно хорошо объясняют различия в обоих, и, что еще лучше, источник для обоих доступен. См. Python/lib/site-packages/pymel/mayautils.py и Python/lib/site-packages/pymel/core/language.py соответственно в вашей установке Maya. - person systemexit; 01.04.2015
comment
Хорошо, спасибо, и единственный способ, которым я мог получить данные из редактора сценариев, был через cmdScrollFieldExecuter( storeContents=True ), который, будучи закомментирован, решает все сбои, поэтому я считаю, что проблема именно в этой команде. Вероятно, это потому, что он также вызывается, когда окно SE закрыто, но, к сожалению, я ничего не могу с этим поделать. - person Peter; 01.04.2015
comment
В любом случае, у меня есть скрипт в рабочем состоянии с гораздо меньшим количеством сбоев, вот он, если вы хотите попробовать его или посмотреть, как он сохраняется - github.com/Peter92/Maya/blob/master/SEAutoSave.py перейдите по ссылке def saveScriptEditorFiles. Кроме того, я впервые пытаюсь правильно комментировать, поэтому некоторые моменты могли быть объяснены неправильно :) - person Peter; 01.04.2015
comment
@Peter Похоже, что единственный раз, когда вы используете executeDeferred, это для операторов печати, но я имел в виду, что вам (потенциально) нужно обернуть любой вызов Maya API или Maya Commands; ни один из них не является потокобезопасным. Ваш поток и основной поток потенциально могут вызывать storeContents одновременно, но если вы выполните deferred, ваш вызов будет поставлен в очередь до следующего события простоя. По этой причине вы должны по крайней мере отложить свою функцию saveScriptEditorFiles, когда вы вызываете ее из своего потока. - person systemexit; 02.04.2015
comment
@Peter Если вам может сойти с рук использование cmdScrollFieldExecuter(storeContents=...), это проще, чем создавать свои собственные, в противном случае вы можете использовать cmdScrollFieldExecuter(query=True, text=True) для получения содержимого поля. - person systemexit; 02.04.2015
comment
Я пытался отложить saveScriptEditorFiles перед тем, как опубликовать вопрос, поэтому я забыл сделать это снова после того, как вы исправили печать, вызывающую сбои. В любом случае, это как бы останавливает сбои, но также удаляет каждый файл, если редактор скриптов закрыт, что странно, поскольку я поставил галочку, чтобы убедиться, что он будет удалять файлы только в том случае, если он собирается сохранить. В любом случае, большое спасибо за идею текста запроса, такую ​​простую и эффективную, и мне никогда не приходило в голову попробовать, ха-ха. Я буду использовать это вместо исправления вышеуказанной проблемы, это кажется намного чище. - person Peter; 03.04.2015

person    schedule
comment
Добро пожаловать в Stack Overflow! Пожалуйста, не отвечайте только исходным кодом. Постарайтесь дать хорошее описание того, как работает ваше решение. См.: stackoverflow.com/help/how-to-answer. Спасибо! - person Matt Ke; 25.02.2019