Odd timer problem

Here is an odd one. I don't know if it is a wx problem, or just a problem of
my own making.

Neither. This is a Windows design decision.

I have found an alternative approach which avoids the issue,
but I thought I would mention it for interest.

My wx program acts as a client in a client/server setup. It makes a
connection to the server on startup, and the connection is maintained as
long as the program is active. I run a separate thread to handle
communication with the server. It all seems to work well.

Every 10 seconds, I send a message to the server to indicate that the client
is still active. The server monitors this and assumes that the client is
inactive if it receives nothing for 30 seconds, whereupon it terminates the
connection. I calculate the 10 second interval by using a wx.Timer. It works
well.

I am now testing the performance of a large grid with 10 000 rows,
retrieving the data from the server, which in turn retrieves it from a
database using a cursor. I tried holding my finger on the Page-Down button,
to see how long it took to scroll all 10 000 rows. If it takes longer than
30 seconds, I find that an MSW client is disconnected by the server. Clearly
wx.Timer is not being triggered while this is happening.

Exactly right. The Windows WM_TIMER message is the lowest-priority
event in a Windows message queue. In fact, the message is treated
specially. When a timer fires, it doesn't really put a WM_TIMER message
in the message queue, like other messages. Instead, it sets a flag in
the internal window structure. When the message queue is completely
empty, the GetMessage API will check to see if the WM_TIMER bit is set,
and if so, only then will it call the handler. Thus, a WM_TIMER will
never fire as long as there is any other message in your message queue.
WM_PAINT is handled exactly the same way.

Thus, as you have seen, WM_TIMER is not necessarily a good choice for a
heartbeat timer.

My alternative approach is to drive the timer from the thread that connects
to the server. I have a continuous loop monitoring the socket. In there I
have inserted a time.time() to store currentTime, and send the message
whenever time.time() - currentTime > 10. This works fine, as it does not
depend on the wx.MainLoop. Whether it is more, or less, or as expensive as
wx.Timer I have no idea, but I will stick with this method unless anyone has
any other suggestions.

Do you do a "sleep" in there to yield the CPU, so you aren't in a tight
loop? If so, then this is a perfectly acceptable solution.

···

On Tue, 31 Jan 2006 10:19:59 +0200, "Frank Millman" <frank@chagford.com> wrote:

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Tim Roberts wrote:

>Here is an odd one. I don't know if it is a wx problem, or just a
>problem of my own making.
>

Neither. This is a Windows design decision.

Thanks, Tim and Robin, for the explanation.

Do you do a "sleep" in there to yield the CPU, so you aren't
in a tight loop? If so, then this is a perfectly acceptable solution.

I have this in my loop -

  r,w,e = select.select(readable,writable,error,0.1)

The 0.1 is a timeout. I have assumed that this gives the same effect as a
'sleep'.

Perhaps you can confirm this.

Thanks

Frank

···

On Tue, 31 Jan 2006 10:19:59 +0200, "Frank Millman" > <frank@chagford.com> wrote:

Frank Millman wrote:

Tim Roberts wrote:

>
> Do you do a "sleep" in there to yield the CPU, so you aren't in a
> tight loop? If so, then this is a perfectly acceptable solution.
>

I have this in my loop -

  r,w,e = select.select(readable,writable,error,0.1)

The 0.1 is a timeout. I have assumed that this gives the same
effect as a 'sleep'.

Perhaps you can confirm this.

After I posted this, I realised I can easily confirm it for myself.

I put a print statement, with a counter, into the loop, and ran it.

I can clearly see that the print statement appears 10 times per second.
Based on that, I guess I am safe.

No need to confirm, unless I am doing something obviously wrong.

Many thanks

Frank

If there is nothing to be done on those sockets, then yes, it is
effectively a time.sleep(.1) . If there is something to be done, the
select call will return when there is something to be done (immediately,
.05 seconds in, etc.), and it won't perform exactly the same.

- Josiah

···

"Frank Millman" <frank@chagford.com> wrote:

Frank Millman wrote:
> Tim Roberts wrote:
>
> >
> > Do you do a "sleep" in there to yield the CPU, so you aren't in a
> > tight loop? If so, then this is a perfectly acceptable solution.
> >
>
> I have this in my loop -
>
> r,w,e = select.select(readable,writable,error,0.1)
>
> The 0.1 is a timeout. I have assumed that this gives the same
> effect as a 'sleep'.
>
> Perhaps you can confirm this.
>

After I posted this, I realised I can easily confirm it for myself.

I put a print statement, with a counter, into the loop, and ran it.

I can clearly see that the print statement appears 10 times per second.
Based on that, I guess I am safe.

No need to confirm, unless I am doing something obviously wrong.

Josiah Carlson wrote:

>
> After I posted this, I realised I can easily confirm it for myself.
>
> I put a print statement, with a counter, into the loop, and ran it.
>
> I can clearly see that the print statement appears 10 times
per second.
> Based on that, I guess I am safe.
>
> No need to confirm, unless I am doing something obviously wrong.

If there is nothing to be done on those sockets, then yes, it
is effectively a time.sleep(.1) . If there is something to
be done, the select call will return when there is something
to be done (immediately,
.05 seconds in, etc.), and it won't perform exactly the same.

- Josiah

Ok, thanks for explaining that.

I am not concerned about it performing exactly the same. I am concerned
about consuming CPU cycles unnecessarily.

I expect the socket to be idle most of the time. When there is something to
be done, I want it to react as quickly as possible. The effect of my change
is that, every time there is something to be done, or every 0.1 sec,
whichever occurs first, the following lines are executed -

    if time.time() - currentTime > 10:
        self.sendTick()
        currentTime = time.time()

Overall, I think this solution is ok.

Any comments?

Thanks

Frank

···

"Frank Millman" <frank@chagford.com> wrote:

That will work fine.

- Josiah

···

"Frank Millman" <frank@chagford.com> wrote:

    if time.time() - currentTime > 10:
        self.sendTick()
        currentTime = time.time()

Overall, I think this solution is ok.
Any comments?