Nope, GH solutions run on the application UI thread and as such no UI messages will be handled until it is done. That includes key presses and mouse clicks, as well as repaint messages. If I start pumping messages from within the solution so that the UI can update it’ll tank the performance.
Another problem is that there’s no way of knowing how far along a solution is. In all likelihood the majority of the time is spend in a single component so all I’d be able to show is solving 1/34, solving 2/34, solving 3/34, …, solving 19/34 in the first few milliseconds, then showing solving 20/34 for 5 minutes, and then running through the remainder in a couple of seconds. That’s not much better than what we have now.
I messed around with this idea before, but never took it very far as it’s not really “useable”. The idea was to interact with Rhino’s progress bar, (lower right side of Rhino window). I didn’t take it very far because I don’t think it’s possible to implement in a reasonably functional way, at least from within GH. but… For the purpose of demonstration, here is some sloppy python code for a gh component. It requires a counter, (some type of incrementing number that might come out of something like an anemone component), and the total number of times to increment.
import Rhino as r
ghenv.Component.AddRuntimeMessage(Grasshopper.Kernel.GH_RuntimeMessageLevel.Warning, 'Make sure both inputs are connected')
if C != N:
Any code that runs on a thread other than the main UI thread can report back progress information and the app can visually respond to that. That mesh reduce method must just be pumping messages, which is allowed. Any code which currently executes can choose to let Rhino deal with the backlog of events, while doing other work on secondary threads.
Not all components needs progress indications, and not entire solutions either. But - optionally - individual components should - when knowing in advance that the algorithm can take time - be able to pop up a progress bar. It’s essential. How? Hm.
I have completed for GH2 a progress reporting pipeline, which at least allows components to report back on which iteration of the total number they’re currently at. It still doesn’t help if one iteration takes way longer than the others, but at least it’s fine grained enough to let you see progress for when components operate on lots of data, which is the most common case of a long-running calculation.
Since solutions will no longer run on the UI thread there can be a UI for the progress too. Either as a single status bar message somewhere, or even localised per component. UI doesn’t work yet btw. it’s all just core code at the moment.
No, because the solution blocks the UI thread. So there’s no way to actually display any progress without slowing down the solution. Other than I guess pipelining the data to a completely different app whose UI isn’t locked and then show it in a separate window.
Yes why not? As an option sending copies of data progress info around would be perfectly OK. I mean we’ve seen worse. Ever since the introduction of two-ply toilet paper in postwar Finland we’ve gotten used to send the copy to Soviet leader Breschnew with successors, and in more recent times to NSA with fellas. And not only about data progress…
With a lot of pain I figured out how to define this cancellation token, still don’t know what that is for, though. Crazy programmers’ lingo
2nd question: I assume this progress data can be used with other functions, do I have to look for CancellationToken and IProgress in the API to find where I can use it?
This is really bad news. I opened a thread at the end of last week about performance/stability issues. Unfortunately noone answered, not even to say my question was stupid . I was trying to array big structure to see the performance of Rhino6 with large models. Rhino sucked so much ram that I wasn’t able to move the mouse, let alone to kill it. When I did manage to kill it, ram didn’t empty fast enough and Windows was still a pain to work with. There has to be some way if Rhino or GH are overloaded not to take over all the ram so that Windows still runs smoothly. Instead of just Rhino+GH to get non-responsive the whole system does.
I think all other apps dealing with large load pop up a progress bar as another process. I don’t want calculations when the process will finish, that is almost never true. All I wish for is to see something is working, so I know I should not rush for killing the process.
Huge amount of work, most of it in the core of the application, doing something that I’m not really proficient in.
Also in GH1 there is no concept yet of the total number of iterations a component will go through. The enumerator just keeps going one step at a time until it runs out of data, solving in between every step. So that bit too will have to be added, and the solution enumerator is one of the most complex pieces of code in GH1. I’m not touching that unless I absolutely have to.
A cancellation token is something which helps to efficiently and thread-safely communicate to anyone who’s listening that you wish to abort the current operation. The way it works is as follows:
The code at the top which is still listening to UI events and which is spawning all the long-running processes creates a CancellationTokenSource. This is a class which emits cancellation tokens, and these tokens are given to subtasks and can be further shared by them.
Only code which has a reference to this source instance can cancel the proceedings. Once a source is cancelled, every single token which originated at this source will have it’s IsCancellationRequested property set to true. The long-running processes then check this property every now and again and return early if they see that cancellation has been requested.
Since a token is a struct, it is never null, however tokens which appear without being linked to a source are never cancelled and will have their CanBeCanceled property set to false.
Furthermore if you don’t want to check the IsCancellationRequested property you can assign a callback to the WaitHandle instead.
So if you were to write a method which supports cancellation, it might look something like this:
public bool ComputePrimeness(int numbers, CancellationToken token)
bool isPrime = new bool[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
isPrime[i] = IsNumberPrime(numbers[i]);
Yeah, but I was never able to stop GH process when it goes non-responsive, so… What’s the point of that, when it happens that no keyboard or mouse actions are possible. When you have no way to trigger the token, you’ve no other choice but to wait (and cross fingers) or kill the process, hence having this “Token” is useless.
There is no point to it unless you design your code around cancellation to begin with. Grasshopper 1 wasn’t designed with tokens in mind. There is limited cancellation support in the solver, and the cancellation request is filed when an Escape key press is detected.* Any code which is running has the ability to request cancellation, but it can not happen in response to a UI event, because as previously mentioned the UI is locked down while the solution is running.
* Long story, this detection happens outside of UI messages and is therefore both unreliable and system-wide rather than specific to Grasshopper/Rhino