Multithreading support (please :) )

The progress so far:

  • any loop in the main thread ( script thread ) will freeze the UI . I was not able to have a long running task in bpy.ops.text.run_sript() without freezing the UI. So you cannot have a thread-safe queue reference created and consumed from that thread.

  • The subprocess module is to split some work in different isolated processes and have IPC using pipes. But it is still bound to the run script thread. It cannot have a long running process in parallel.

  • the multiprocessing module is to have a totally separate process doing work for you but the bpy module from the main blender process is not accessible from the new process. From my simple test it looks like it creates a new blender context. Seems to be the same as having a headless blender instance.

The code:

import multiprocessing
import time
import bpy
from random import randint

def daemon():
    p = multiprocessing.current_process()
    print('Starting:', p.name, p.pid)
    
    try:
        print("Current cube location")
        print(bpy.data.objects['Cube'].location)
        print("Execute move")
        bpy.data.objects['Cube'].location.x += 0.10
        print("After move cube location")
        print(bpy.data.objects['Cube'].location)

        bpy.ops.mesh.primitive_cube_add(location=(randint(-10,10),randint(-10,10),randint(-10,10)))
        print("Adding a new cube as Cube.001")
        for x in range(len(bpy.data.objects)): 
            print( bpy.data.objects[x])
    except Exception as e:
        print("An exception occurred")
        print(e)

    time.sleep(5)
    print('Exiting :', p.name, p.pid)
    
d = multiprocessing.Process(name='daemon', target=daemon)
d.daemon = True
d.start()

@Skarn thanks for the suggestion. I did tried to see if calling such function from the other thread would work… it did not :slight_smile: ( as expected )

from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
import bpy
from random import randint


def simpleCubeAdd():
    print(threading.current_thread().name, "adding a new cube")
    bpy.ops.mesh.primitive_cube_add(location=(randint(-10,10),randint(-10,10),randint(-10,10)))
bpy.app.driver_namespace["simpleCubeAdd"] = simpleCubeAdd

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        import bpy
        bpy.app.driver_namespace["simpleCubeAdd"]()
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'Hello, world!')
 
class ServerThread(threading.Thread):
     def __init__(self,port):
         super(ServerThread, self).__init__()
         self.port=port
 
     def run(self):
         httpd = HTTPServer(('localhost', self.port), SimpleHTTPRequestHandler)
         httpd.serve_forever()
 
if "server" in bpy.app.driver_namespace.keys():
    if(bpy.app.driver_namespace["server"].isAlive()):
        print("server thread is alive, try stoping it")
        bpy.app.driver_namespace["server"].stop() # TBD
else:
    print("server is not alive, starting now")
    bpy.app.driver_namespace["server"] = ServerThread(8000)
    bpy.app.driver_namespace["server"].setDaemon(True)
    bpy.app.driver_namespace["server"].start()