It is currently March 29th, 2024, 1:26 am

Some explanation of timing and WebParser

Tips and Tricks from the Rainmeter Community
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Some explanation of timing and WebParser

Post by jsmorley »

There was a thread in another area where I touched on all this, and I thought it would be better to have it someplace I can find it again in case it comes up.

How you manage timing with WebParser

1) A skin has an Update option set in [Rainmeter], which controls how often the overall skin is updated. On each Update, Rainmeter will go through the entire skin updating values and options for measures and meters in the order they are in the skin, then redraws the entire skin on the screen. The default for this is 1000 milliseconds.

2) Measures (and meters) have an UpdateDivider option that tells Rainmeter that you only want to update that measure every UpdateDivider Updates. So (Update * UpdateDivider). The default for this is 1. That is how you can have a skin that updates every second, (Update=1000) but an individual measure that only updates every 5 seconds. (UpdateDivider=5)

3) WebParser also has an UpdateRate option. This is tracked internally in the plugin, not by the skin. What happens is that every time the measure is updated by the skin, the plugin increments a counter, from 0 to UpdateRate. When the counter reaches UpdateRate, it is reset to 0. Whenever that counter is 0, the WebParser plugin starts a separate process thread that goes out to the internet, downloads and parses the data. So it is (Update * UpdateDivider * UpdateRate). The default for this is 600. That is equal to every 10 minutes if you have the default Update=1000 and UpdateDivider=1.

So the real meat and potatoes functionality is executed in a thread when the skin is first loaded, (the counter is 0) when it is refreshed, (the counter is 0) or UpdateRate is reached. (the counter is reset to 0)

Why does UpdateRate exist? The reason is that a WebParser measure can take a long time (relatively speaking) to download and parse a huge site on a slow WiFi connection. We don't want a WebParser measure to "block" Rainmeter while it is dong so, so instead of the way it works with most measures, where in a sense Rainmeter asks the measure for an answer and gets it right then, Rainmeter asks WebParser for an answer, but doesn't stick around waiting for it. The plugin starts a separate process thread that does the downloading and parsing, and populates the parent and all child WebParser measures with values when it is finished. The real work WebParser does, other than tracking that counter/UpdateRate, is off in a separate thread that doesn't impact the performance of Rainmeter.

UpdateRate allows you to leave UpdateDivider on the measure at the default of 1, (just leave it off the measure entirely) so other measures or meters asking for the values returned by the parsing will be able to get the string or number values immediately as soon as the parsing is done. If you try to use UpdateDivider instead of UpdateRate to control a WebParser measure, there can be some "lag" before number values are available to formulas in other measures or meters. You also want to ensure that other functions on the measure, that are not related to parsing the resource, like FinishAction, OnUpdateAction, OnChangeAction, Substitute, IfEqual/IfMatch/IfCondition etc. are resolved as soon as possible after the parsing is done.


UpdateDivider and UpdateRate should almost never be used on "child" WebParser measures. Child WebParser measures are populated by, and in a sense entirely controlled by, the "parent" measure. UpdateRate is ignored on child measures, and UpdateDivider can only cause hideous problems with some behavior of the child measure being "out of sync" with its parent.

The long and the short of it is that it is almost always best to leave UpdateDivider off of WebParser measures entirely, and use UpdateRate on the parent WebParser measure to control timing.

4) If you want to have an action cause a WebParser parent measure to override UpdateRate and execute the resource download and parse on demand, you must use The bang [!CommandMeasure MeasureName "Update"]. This bang will tell the plugin to immediately reset its internal counter to 0. In other words, to go out to the internet, get data and parse it right now.

Remember that if you [!UpdateMeasure MeasureName] a WebParser measure, all you are really doing is incrementing that internal UpdateRate counter by 1. The plugin still won't do anything else until the value for UpdateRate is reached and the counter is reset to 0. The bang [!CommandMeasure MeasureName "Update"] is really the only way to "poke" a WebParser measure.

5) The WebParser plugin will populate values in the parent and all child measures immediately when the parsing is done. That means that as soon as the parsing is done, the values will immediately be available to other measures and meters when they "ask for them".

When practical, other measures or meters using WebParser data should be set to themselves update on each update of the overall skin, with UpdateDivider=1. That way the data from WebParser will be used pretty much as soon as the parsing is done. If performance or other considerations make this a problem, you can use a FinishAction on the WebParser parent measure, and use the !UpdateMeasure / !UpdateMeter / !Redraw bangs to have the WebParser measure "prompt" other measures and meters to come get and use the newly parsed data right now.

Extra credit:

If you really follow that mess above, it gives a hint as to why sometimes WebParser can just get "hung" if you repeatedly and rapidly "refresh" the skin while testing, or if you set UpdateRate so low or use !CommandMeasure so often it can't finish one request before it is asked to do another.

What happens when the skin is refreshed or UpdateRate is reached is that the plugin kicks off a thread to go out to the internet to get and parse the data. When you again refresh the skin or otherwise tell WebParser to go out again, before it is done accomplishing that task, the plugin interrupts and "kills" that running thread, throws away anything it has already gotten, kicks off a new thread and starts over. This is generally fine. However, a WebParser thread executes some things that are external to Rainmeter, mostly some Internet Explorer API's and a PCRE runtime library for regular expression. These may or may not take kindly to being "nuked" over and over while they are in the middle of doing something. The problem comes when you do this repeatedly in a short period of time. The system just gets overwhelmed managing these threads you are abusing, (they take a little time to gracefully "die") and eventually just "hangs" the thread, and thus that instance of the plugin. The plugin can no longer "kill" that hung thread, and so never starts a new one. It just sits there doing nothing forever. Rainmeter keeps working, everything else in the skin is fine, but WebParser in that skin is paralyzed.

Refreshing the skin won't help. Unloading and reloading the skin won't help. Only a complete restart of Rainmeter will get that instance of the plugin, in that skin, working again. Windows itself can and will "clean up" any running (even hung) .dll programs that are still loaded when the "parent" application (Rainmeter.exe in this case) exits.
drakulaboy
Posts: 165
Joined: June 29th, 2014, 8:35 pm

Re: Some explanation of timing and WebParser

Post by drakulaboy »

this is really explaining a lot
in my skin i have

Code: Select all

Update=10000
so when i load my skin, parser it's doing his job to download data and after 10 seconds it's loading on skin, and on parsed measure i have

Code: Select all

UpdateRate=60
UpdateDivider=1
is it good to have UpdateRate and UpdateDivider functions on that measure? or do i need only UpdateRate?
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Some explanation of timing and WebParser

Post by jsmorley »

drakulaboy wrote:this is really explaining a lot
in my skin i have

Code: Select all

Update=10000
so when i load my skin, parser it's doing his job to download data and after 10 seconds it's loading on skin, and on parsed measure i have

Code: Select all

UpdateRate=60
UpdateDivider=1
is it good to have UpdateRate and UpdateDivider functions on that measure? or do i need only UpdateRate?
It's entirely up to you. I don't believe I have ever written a skin where I set Update higher than the default 1000. There are lots of good reasons to set it lower than that, but I have never found occasion where I found it better to have the entire skin update slowly, rather than just leaving Update=1000 and using UpdateDivider/UpdateRate where needed to control timing and keep things efficient.

An exception might be a really massive full-screen skin with just tons of meters. Particularly if the meters are images that are being resized when they are drawn. The only function of Rainmeter that can ONLY be controlled by Update, that will always happen on every update, is the skin "redraw". All "updating" can be controlled by UpdateDivider, even on meters, but the entire skin will always be redrawn on the screen on every Update. So I guess I could envision a situation where it might be marginally more efficient to have the skin Update set higher, to keep the number of redraws to a minimum, those can be a tad expensive with a large skin that has to resize images and redraw a significant portion of the entire screen.

Just keep in mind that while you can always use UpdateDivider/UpdateRate to have measures or meters update "slower" than the overall Update rate, nothing can ever be "faster" than the overall Update rate. Once you set Update=10000, that is the fastest that anything in the skin can update without a mouse event.


I do have a skin or two where I set Update=-1, so it only updates the skin once when loaded, but that is pretty much for something like a launcher / dock or other situations where the skin doesn't do anything on its own, and is entirely "event driven" by the mouse. In that case, there is really no need to have the skin "update" at all once loaded.

With Update=10000, the WebParser plugin will go out, download and parse the resource, and set the values for the parent and child WebParser measures immediately as soon as the parsing is done. However, any other measures or meters that use that data will wait for the next skin update, 10 seconds later, to actually come get and use the data. That few seconds "lag" will only be noticeable when you first load or refresh the skin, which I wouldn't particularly like myself, but it won't matter all that much if you really have some good reason to set Update=10000.

But in any case, what you are doing with Update / UpdateRate / UpdateDivider is fine. The default for UpdateDivider is 1, so you don't even really need it on a WebParser measure, but setting it to 1 won't hurt anything.

I personally would NEVER use any UpdateDivider on a WebParser measure. Even if you have a skin that also has animations set to Update=50 or something, having Rainmeter update a WebParser measure and increment the UpdateRate counter in the plugin is one of the least expensive things Rainmeter does. You certainly can use UpdateDivider to get back the normal behavior of updating the measure once a second, but I'm not sure I would ever bother. The REAL work that WebParser does is done in the plugin thread, which has no impact on Rainmeter performance, and is controlled by UpdateRate.

So if Update=100 but you still wanted to go out to the site every 10 minutes, you would use UpdateRate=6000. Don't use UpdateDivider=10 and the default UpdateRate=600 as that can in some cases cause that "lag" we have talked about, even if just a tiny amount. I can see no reason why you wouldn't always want to get and display the result of a WebParser measure as close to as soon as it actually "has it" as practical.