Could someone explain to me what exactly is updated when Timer component is added to a ghpython component?
if the component is in GH_Component SDK mode:
The problem is I want to create a random number on every update and if that number is smaller or greater than a certain value I want to change the domain of the randomizer. In a way mimic Galapagos functionality.
Since this updates the whole script I always get the same values for min and max of the domain (the initial values) because the script is always run from the beginning from the Timer.
I tried to use two components one generating random values, and other one defining the min and max values, but that leads to a cycle error.
Edit: @piac, @DavidRutten is this even possible without compiling or maybe using Timer is the wrong way in this case?
no, the whole script is NOT executed again. Your class is instantiated only once at the beginning, and then RunScript() is run once for every time it is needed (may be thousand of times per solution).
If you want to set some logic at component creation or deletion, you can override Python’s initialization/deletion methods:
but that one relies on the Garbage Collector, and may happen in a very remote time from apparent deletion of the component (use with extreme caution: throwing exceptions in a Garbage Collector call will immediately close the program, and bugs are hard to debug).
Do not rely on what happens in the external scope when using the SKD-mode (object-oriented mode). It’s an implementation detail.
RH-47124 is an optimization that I added. The outer scope will no longer be evaluated before invoking the RunScript() def, when in SDK mode. Only at the reset of the script it will be re-evaluated.
Thanks,
Giulio
–
Giulio Piacentino
for Robert McNeel & Associates giulio@mcneel.com
Sorry for the delay, it was faster to use what Giulio suggested so I started with that.
Thanks for sharing this solution, it is really useful.
I have one question though, how can I slow the update? Not that I want to make it ineffective I just want some more time to debug
UPDATE:
Never mind, I got it. time.sleep(1) inside the update definition.
That’ll simply pause the Python interpreter, you probably want to set a higher interval on the ghDoc.ScheduleSolution() call instead. Also, I find that recording (using the standard GH recorder) the GHPython output parameter is a good way of debugging dynamic/iterative/time-dependent components.
Btw I found out that using time.sleep in fact makes grasshopper to stutter.
If my definition is running and self-updating and has time.sleep in the update when zooming in grasshopper it does so every second at a time.
Another strange thing is, if Timer component is apparent and active on the canvas, the interval of ghDoc.ScheduleSolution() is ignored.
The scheduling works as designed. Everyone is allowed to schedule a solution, but only the earliest schedule is remembered. So if you tell GH you want a solution one second from now, and then some other component requests a solution 10 milliseconds from now, there will be another solution 10ms from now and that’s it. You either have to do the work you were planning to do right there and then (earlier than expected, but maybe that doesn’t matter?), or you must schedule another solution 990ms from now. Keep doing that until a solution starts that is close enough to your desired time.
10ms will fire first. And then nothing will fire unless another solution is scheduled during or after that 10ms solution.
Here, in a nutshell, is the scheduling logic:
private TimeSpan _schedule;
private List<delegate> _callbacks = new List<delegate>();
public void ScheduleSolution(TimeSpan delay, delegate callback)
{
_callbacks.Add(callback);
if (delay < _schedule)
_schedule = delay;
if (!SolutionRunning)
BeginScheduleTimer();
}
public void RunSolution()
{
SolutionRunning = true;
_schedule = TimeSpan.Zero;
foreach (delegate callback in _callbacks)
callback.Invoke();
_callbacks.Clear();
// Iterate over all expired objects and solve them.
// Some of them may schedule solutions while running.
SolutionRunning = false;
if (_schedule != TimeSpan.Zero)
BeginScheduleTimer();
}