Skip to content

Commit

Permalink
CAP-WIP: working version for thread safe elimination
Browse files Browse the repository at this point in the history
  • Loading branch information
9and3 committed Jan 28, 2024
1 parent a1bf3a6 commit f36e559
Showing 1 changed file with 66 additions and 40 deletions.
106 changes: 66 additions & 40 deletions GH/PyGH/scriptsyncGH_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,49 @@

import threading

# from System.Threading import Thread
# from functools import partial

import rhinoscriptsyntax as rs


def update_component():
""" Fire the recalculation of the component solution. """
# clear the output
ghenv.Component.Params.Output[0].ClearData()
# # expire the component
ghenv.Component.ExpireSolution(True)
class ScriptSyncThread(threading.Thread):
def __init__(self, path, path_lock, name):
super().__init__(name=name, daemon=False)
self.path = path
self.path_lock = path_lock
self.component_on_canvas = True

def check_file_change(path, path_lock):
"""
Check if the file has changed on disk.
:param path: The path of the file to check.
:returns: True if the file has changed, False otherwise.
"""
with path_lock:
last_modified = os.path.getmtime(path)
while True:
System.Threading.Thread.Sleep(1000)
def run(self):
self.check_file_change(self.path, self.path_lock)

def check_if_component_on_canvas(self):
""" Check if the component is on canvas. """
if ghenv.Component.OnPingDocument() is None:
self.component_on_canvas = False

def update_component(self):
""" Fire the recalculation of the component solution. """
ghenv.Component.Params.Output[0].ClearData() # clear the output
ghenv.Component.ExpireSolution(True) # expire the component

def check_file_change(self, path, path_lock):
"""
Check if the file has changed on disk.
current_modified = os.path.getmtime(path)
if current_modified != last_modified:
last_modified = current_modified
action = System.Action(update_component)
Rhino.RhinoApp.InvokeOnUiThread(action)
break
return
:param path: The path of the file to check.
"""
with path_lock:
last_modified = os.path.getmtime(path)
while self.component_on_canvas:
System.Threading.Thread.Sleep(1000)
Rhino.RhinoApp.InvokeOnUiThread(System.Action(self.check_if_component_on_canvas))

if not self.component_on_canvas:
print(f"script-sync::Thread {self.name} aborted")
break

current_modified = os.path.getmtime(path)
if current_modified != last_modified:
last_modified = current_modified
Rhino.RhinoApp.InvokeOnUiThread(System.Action(self.update_component))


def safe_exec(path, globals, locals):
Expand Down Expand Up @@ -77,12 +88,14 @@ def __init__(self):
self._var_output = ["None"]
ghenv.Component.Message = "ScriptSyncCPy"

self.thread = None
# self.thread = None
self.thread_name = None
self.path = None
self.path_lock = threading.Lock()

# print(f'Number of scriptsync_threads: {len(threading.enumerate())}')

# FIXME: output cannot be set by componentizer, redirect the output of python to
# a custom string output

def RunScript(self, x, y):
""" This method is called whenever the component has to be recalculated. """
# check the file is path
Expand All @@ -93,17 +106,28 @@ def RunScript(self, x, y):

print(f"script-sync::x value: {x}")

# share the self.path resource among threads


# # non-blocking thread
# action = partial(check_file_change, self.path)
# Rhino.RhinoApp.InvokeOnUiThread(action)
# self.thread = Thread(partial(check_file_change, self.path))
# self.thread.Start()

thread = threading.Thread(target=check_file_change, args=(self.path, self.path_lock))
thread.start()
# # FIXME: the thread is created new every time the component is executed, it should not be like this
# get the guid instance of the component
self.thread_name : str = f"script-sync-thread::{ghenv.Component.InstanceGuid}"
if self.thread_name not in [t.name for t in threading.enumerate()]:
# # the thread already exists, we need to abort it
# for t in threading.enumerate():
# if t.name == self.thread_name:
# t.abort()
# print(f"script-sync::Thread {self.thread_name} aborted")
# break
ScriptSyncThread(self.path, self.path_lock, self.thread_name).start()
# thread = threading.Thread(target=check_file_change,
# args=(self.path, self.path_lock),
# daemon=False,
# name=self.thread_name)
# thread.start()
print(f'Number of scriptsync_threads: {len(threading.enumerate())}') #<<<
for t in threading.enumerate():
print(t.name) #<<<




Expand All @@ -128,13 +152,15 @@ def RunScript(self, x, y):
if k in outparam_names:
self._var_output.append(v)


return self._var_output

# FIXME: problem with indexing return
# FIXME: problem with indexing return
def AfterRunScript(self):
outparam = ghenv.Component.Params.Output
for idx, outp in enumerate(outparam):
if outp.NickName != "out":
# if outp.NickName == self._var_output[idx]:
ghenv.Component.Params.Output[idx].VolatileData.Clear()
ghenv.Component.Params.Output[idx].AddVolatileData(gh.Kernel.Data.GH_Path(0), 0, self._var_output[idx])
self._var_output = ["None"]

0 comments on commit f36e559

Please sign in to comment.