[Haskell-cafe] scheduling an alarm

Thomas DuBuisson thomas.dubuisson at gmail.com
Wed Jan 27 11:25:05 EST 2010

On Wed, Jan 27, 2010 at 7:31 AM, Brian Denheyer <briand at aracnet.com> wrote:

> On Tue, 26 Jan 2010 22:41:44 -0800
> Thomas DuBuisson <thomas.dubuisson at gmail.com> wrote:
> > Brian Denheyer <briand at aracnet.com> wrote:
> >
> > > On Tue, 26 Jan 2010 10:54:03 -0800
> > > Thomas DuBuisson <thomas.dubuisson at gmail.com> wrote:
> > >
> > > > > doEvent f usDelay = forkIO $
> > > > >   threadDelay usDelay
> > > > >   doEvent f usDelay
> > > > >   f
> > >
> > > Are you sure that's right ? It seems to be a memory-gobbling
> > > infinite loop...
> > >
> >
> > Infinite loop?  yes, that is what you wanted.  Memory gobbling?  Why
> > would you think that? Are you assuming no TCO and a full stack push
> > on every function call?  Haskell compilers don't work that way.
> Why would I think that ?
> I think that because the following code:
> import Control.Concurrent
> f = putStrLn "foo"
> doEvent f usDelay = do forkIO $ threadDelay usDelay
>                       doEvent f usDelay
>                       f
> _really_ _does_ start to consume all of the memory on my system, that's
> why.  I don't know why, but that's what it does on my system.  It's not
> obvious to me that it should do that.  So maybe ghci is not doing TCO.

That would be a bug!  I'm using GHC 6.12.1 i386 and both interpreted using
GHCi CLI and compiled (even without optimization) there is no memory growth
using either of the two versions.  If you are using the latest GHC then
consider filing a report at haskell.org/ghc

> 2) It strikes me as funny you suspect the first way when there is zero
> > fundamental difference between that and the way you posted except
> > that: a) My version maintains the correct delay.
> > b) My version forks the doEvent call and runs the action in the older
> > thread while yours forks the action thread and keeps the doEvent in
> > the older thread.  I suppose keeping the doEvent as the old thread is
> > good so you can kill it with the original ThreadID that would be
> > returned to the caller.
> >
> Thanks for the explanation, as I said I'm a little fuzzy on what
> constitutes a thread, so the two versions will help.

Well Concurrent Haskell has a version of green threads [1] which are
scheduled (via the GHC RTS) on some number of OS threads (typically either 1
or equal to the number of cores on the machine).  These light weight "green
threads" are extremely cheap to create and destroy, costing a matter of 1K
or less per thread, benchmarks can create/destory 100k threads in seconds.
"forkIO" creates green threads while "forkOS" (which you generally should
not use) creates OS threads.

One interesting thing I noticed in the docs (which is not important
> for what I am trying to do, just interesting):
> There is no guarantee that the thread will be rescheduled promptly when
> the delay has expired, but the thread will never continue to run
> earlier than specified.

Right, and this is the same as any commodity OS - you can delay for a
certain amount of time and once the delay is up you will get rescheduled but
the computer is likely busy with other processes/interrupts etc at the exact
microsecond you are done.  I think the GHC RTS schedules threads in 50us
slices by default.  Also, GHC uses (or used to use) allocation as a
scheduling point so if you have long-running tight loops that don't allocate
(and don't explicitly call 'yield') then this could be quite long. In
practice I've only once had a problem (GTK GUI didn't update during a long
computation - still not sure this was the reason).


[1] http://en.wikipedia.org/wiki/Green_threads
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20100127/a04dfbea/attachment.html

More information about the Haskell-Cafe mailing list