MRが楽しい

MRやVRについて学習したことを書き残す

Blender 2.8のPython APIドキュメントを少しずつ読み解く 落とし穴 その8

本日は Blender2.8 の調査枠です。
Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。
前回記事の続きです。
bluebirdofoz.hatenablog.com

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試して記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「落とし穴」の「スレッド化モジュールを使用したエラー」です。
f:id:bluebirdofoz:20200118215734j:plain

スレッド化モジュールを使用したエラー

BlenderでのPythonスレッドは、スクリプトが終了する前にスレッドが終了したときにのみ適切に機能します。
例えば threading.join() を使用した場合です。

Blenderでサポートされているスレッドの例を次に示します。

import threading
import time

def prod():
    print(threading.current_thread().name, "Starting")

    # do something vaguely useful
    import bpy
    from mathutils import Vector
    from random import random

    prod_vec = Vector((random() - 0.5, random() - 0.5, random() - 0.5))
    print("Prodding", prod_vec)
    bpy.data.objects["Cube"].location += prod_vec
    time.sleep(random() + 1.0)
    # finish

    print(threading.current_thread().name, "Exiting")

threads = [threading.Thread(name="Prod %d" % i, target=prod) for i in range(10)]


print("Starting threads...")

for t in threads:
    t.start()

print("Waiting for threads to finish...")

for t in threads:
    t.join()

f:id:bluebirdofoz:20200118215744j:plain
f:id:bluebirdofoz:20200118215755j:plain

次は1秒間に何回も実行され、デフォルトのキューブを連続的に移動する(サポートされていない)タイマーの例です。

import threading
import time

def func():
    print("Running...")
    import bpy
    bpy.data.objects['Cube'].location.x += 0.05

def my_timer():
    from threading import Timer
    t = Timer(0.1, my_timer)
    t.start()
    func()

my_timer()

f:id:bluebirdofoz:20200118215804j:plain
f:id:bluebirdofoz:20200118215813j:plain

スクリプトが終了するとスレッドを実行したままにする上記のユースケースは、しばらくは動作するように見えます。
しかし、Blender自身の描画コードでランダムなクラッシュまたはエラーを引き起こすことになります。

これまでのところ、BlenderPython統合スレッドを安全にする作業は行われていません。
そのため、スレッドが適切にサポートされるまで、これを使用しないでください。

bluebirdofoz.hatenablog.com