STM, IO and event loops

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

STM, IO and event loops

Joel Reymont
Folks,

I'm trying to build an event-driven system that includes multiple  
event channels. I would have one channel for network events and  
another one for events sent by other threads. I would like to use STM  
and `orElse` to poll the various event channels.

Is there a reasonably safe way to do this with STM and IO?

The network side of things currently times out after a given number  
of seconds if no input is available but can also throw exceptions.  
I'm having a hard time figuring out how to wrap this in STM.

There's another alternative that I can think of...

My poker bots are launched in separate threads but do not talk to  
each other right now. They just receive events from the network. I  
would like a poker bot to tell others to stop playing and exit, for  
example. I guess I could build poker bots with an event loop that  
reads from a TChan but... I would then need twice as many threads  
since each bot has a socket associated with it and one thread per bot  
would need to read from the socket and push events into the TChan.

Are there any facilities in Haskell that can poll a set of 10k  
descriptors and retrieve input from the first available?

I don't know if I should be concerned with launching 20k threads vs.  
10k threads but it seems that disassociating bots from the network  
has some positive effects. I could compose packets by hand in the  
interpreter and feed them to the TChan by hand to test individual  
bots, for example.

Any advice is appreciated!

        Thanks, Joel

--
http://wagerlabs.com/





_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM, IO and event loops

Bulat Ziganshin
Hello Joel,

Sunday, November 27, 2005, 2:12:23 PM, you wrote:

JR> My poker bots are launched in separate threads but do not talk to
JR> each other right now. They just receive events from the network. I  
JR> would like a poker bot to tell others to stop playing and exit, for  
JR> example.

use async exceptions to do it

JR> 10k threads but it seems that disassociating bots from the network
JR> has some positive effects. I could compose packets by hand in the  
JR> interpreter and feed them to the TChan by hand to test individual  
JR> bots, for example.

as Tomasz already suggested, your bots must be parametrized by
action which gets next item, not by Chan/... itself.

current implementation:

bot chan = ... x<-readChan chan

must be:

bot reading = ... x<-reading
...
top_level = ... chan <- newChan
                forkIO $ bot (readChan chan)
                forkIO $ another_procedure (writeChan chan)

--
Best regards,
 Bulat                            mailto:[hidden email]



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

RE: STM, IO and event loops

Simon Peyton Jones
In reply to this post by Joel Reymont
A good design pattern, I think, is to have a Haskell thread dedicated to
each socket.  It can suck on the socket and dump what it finds into an
STM channel or buffer.  Then other threads (the ones doing the work) can
read it transactionally.  

It should be find to have lots of threads, esp if most of them are
asleep.  The only thing to watch out for is that GHC's runtime system
will consume one *OS* thread for each *blocked* foreign call.  So if you
have 10k threads each making a separate call to the OS to read from 10k
sockets, and they all block, you'll use 10k OS threads, and that will
probably fail.

Simon

| -----Original Message-----
| From: [hidden email]
[mailto:[hidden email]] On Behalf Of Joel
| Reymont
| Sent: 27 November 2005 11:12
| To: Haskell Cafe
| Subject: [Haskell-cafe] STM, IO and event loops
|
| Folks,
|
| I'm trying to build an event-driven system that includes multiple
| event channels. I would have one channel for network events and
| another one for events sent by other threads. I would like to use STM
| and `orElse` to poll the various event channels.
|
| Is there a reasonably safe way to do this with STM and IO?
|
| The network side of things currently times out after a given number
| of seconds if no input is available but can also throw exceptions.
| I'm having a hard time figuring out how to wrap this in STM.
|
| There's another alternative that I can think of...
|
| My poker bots are launched in separate threads but do not talk to
| each other right now. They just receive events from the network. I
| would like a poker bot to tell others to stop playing and exit, for
| example. I guess I could build poker bots with an event loop that
| reads from a TChan but... I would then need twice as many threads
| since each bot has a socket associated with it and one thread per bot
| would need to read from the socket and push events into the TChan.
|
| Are there any facilities in Haskell that can poll a set of 10k
| descriptors and retrieve input from the first available?
|
| I don't know if I should be concerned with launching 20k threads vs.
| 10k threads but it seems that disassociating bots from the network
| has some positive effects. I could compose packets by hand in the
| interpreter and feed them to the TChan by hand to test individual
| bots, for example.
|
| Any advice is appreciated!
|
| Thanks, Joel
|
| --
| http://wagerlabs.com/
|
|
|
|
|
| _______________________________________________
| Haskell-Cafe mailing list
| [hidden email]
| http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM, IO and event loops

Joel Reymont
This is exactly what I do. I use hGetBuf with a timeout. I do not  
compile with -threaded, should I? Does it change anything?

Also, is there a way to somehow stick all the sockets that I read  
from into a select to monitor input on any of them and wake up a  
thread once input becomes available? I do not need to be cross-
platform here and would be fine so long as it works on Unix.

I understand there is threadWaitRead :: Fd -> IO (). Would it do the  
trick for me? Would it do it in a cross-platform fashion?

The function is broken on MingGW as per Conc.lhs, is GHC for Windows  
always compiled under MinGW?

Otherwise threadWaitRead is defined like this:

waitForReadEvent :: Fd -> IO ()
waitForReadEvent fd = do
   m <- newEmptyMVar
   atomicModifyIORef pendingEvents (\xs -> (Read fd m : xs, ()))
   prodServiceThread
   takeMVar m

and I also see this:

buildFdSets maxfd readfds writefds [] = return maxfd
buildFdSets maxfd readfds writefds (Read fd m : reqs) = do
   fdSet fd readfds
   buildFdSets (max maxfd fd) readfds writefds reqs
buildFdSets maxfd readfds writefds (Write fd m : reqs) = do
   fdSet fd writefds
   buildFdSets (max maxfd fd) readfds writefds reqs

This tells me that calling threadWaitRead is the way to go since it  
seems like it will add the fd to select () or some such on non-
Windows platforms. Am I right and what happens on Windows then?

        Thanks, Joel

On Nov 28, 2005, at 8:57 AM, Simon Peyton-Jones wrote:

> It should be find to have lots of threads, esp if most of them are
> asleep.  The only thing to watch out for is that GHC's runtime system
> will consume one *OS* thread for each *blocked* foreign call.  So  
> if you
> have 10k threads each making a separate call to the OS to read from  
> 10k
> sockets, and they all block, you'll use 10k OS threads, and that will
> probably fail.

--
http://wagerlabs.com/





_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

RE: STM, IO and event loops

Simon Marlow
In reply to this post by Joel Reymont
On Unix with -threaded, all blocking I/O using Handles or sockets goes
via the I/O manager thread, which multiplexes all the blocked I/O
requests into a single select() call.  If you have 20k blocked socket
reads, there will be 20k lightweight Haskell threads, and probably 2 or
3 real OS threads.  Without -threaded the outcome is pretty much the
same, except the runtime does the select().

On Windows, unfortunately you'll get 20k OS threads for this scenario
(regardless of -threaded), because we haven't implemented the I/O
manager on Windows yet.

So, to answer the question:

>> Are there any facilities in Haskell that can poll a set of 10k
>> descriptors and retrieve input from the first available?

Yes, you have one forkIO thread per descriptor, and you do your I/O
using standard Handle I/O or Network.Socket.recvfrom/sendto.
Unfortunately it'll be expensive on Windows right now, but the best way
to fix this would be to implement the I/O manager (in GHC.Conc) rather
than doing the multiplexing explicitly in your app code.

Cheers,
        Simon

On 28 November 2005 08:57, Simon Peyton-Jones wrote:

> A good design pattern, I think, is to have a Haskell thread dedicated
> to each socket.  It can suck on the socket and dump what it finds
> into an STM channel or buffer.  Then other threads (the ones doing
> the work) can read it transactionally.
>
> It should be find to have lots of threads, esp if most of them are
> asleep.  The only thing to watch out for is that GHC's runtime system
> will consume one *OS* thread for each *blocked* foreign call.  So if
> you have 10k threads each making a separate call to the OS to read
> from 10k sockets, and they all block, you'll use 10k OS threads, and
> that will probably fail.
>
> Simon
>
>> -----Original Message-----
>> From: [hidden email]
> [mailto:[hidden email]] On Behalf Of Joel
>> Reymont
>> Sent: 27 November 2005 11:12
>> To: Haskell Cafe
>> Subject: [Haskell-cafe] STM, IO and event loops
>>
>> Folks,
>>
>> I'm trying to build an event-driven system that includes multiple
>> event channels. I would have one channel for network events and
>> another one for events sent by other threads. I would like to use STM
>> and `orElse` to poll the various event channels.
>>
>> Is there a reasonably safe way to do this with STM and IO?
>>
>> The network side of things currently times out after a given number
>> of seconds if no input is available but can also throw exceptions.
>> I'm having a hard time figuring out how to wrap this in STM.
>>
>> There's another alternative that I can think of...
>>
>> My poker bots are launched in separate threads but do not talk to
>> each other right now. They just receive events from the network. I
>> would like a poker bot to tell others to stop playing and exit, for
>> example. I guess I could build poker bots with an event loop that
>> reads from a TChan but... I would then need twice as many threads
>> since each bot has a socket associated with it and one thread per bot
>> would need to read from the socket and push events into the TChan.
>>
>> Are there any facilities in Haskell that can poll a set of 10k
>> descriptors and retrieve input from the first available?
>>
>> I don't know if I should be concerned with launching 20k threads vs.
>> 10k threads but it seems that disassociating bots from the network
>> has some positive effects. I could compose packets by hand in the
>> interpreter and feed them to the TChan by hand to test individual
>> bots, for example.
>>
>> Any advice is appreciated!
>>
>> Thanks, Joel
>>
>> --
>> http://wagerlabs.com/
>>
>>
>>
>>
>>
>> _______________________________________________
>> Haskell-Cafe mailing list
>> [hidden email]
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM, IO and event loops

Joel Reymont

On Nov 28, 2005, at 11:32 AM, Simon Marlow wrote:

> On Unix with -threaded, all blocking I/O using Handles or sockets goes
> via the I/O manager thread, which multiplexes all the blocked I/O
> requests into a single select() call.  If you have 20k blocked socket
> reads, there will be 20k lightweight Haskell threads, and probably  
> 2 or
> 3 real OS threads.  Without -threaded the outcome is pretty much the
> same, except the runtime does the select().

I'm not well-versed on the differences between select in the I/O  
manager and the runtime. What is the difference? Should I just plug -
threaded into my cabal file and not worry about it? How big of an  
impact is select() in the runtime?

> On Windows, unfortunately you'll get 20k OS threads for this scenario
> (regardless of -threaded), because we haven't implemented the I/O
> manager on Windows yet.

I will dump Windows any day.

        Thanks, Joel

--
http://wagerlabs.com/





_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

RE: STM, IO and event loops

Simon Marlow
In reply to this post by Joel Reymont
On 28 November 2005 11:47, Joel Reymont wrote:

> On Nov 28, 2005, at 11:32 AM, Simon Marlow wrote:
>
>> On Unix with -threaded, all blocking I/O using Handles or sockets
>> goes via the I/O manager thread, which multiplexes all the blocked
>> I/O requests into a single select() call.  If you have 20k blocked
>> socket reads, there will be 20k lightweight Haskell threads, and
>> probably 2 or 3 real OS threads.  Without -threaded the outcome is
>> pretty much the same, except the runtime does the select().
>
> I'm not well-versed on the differences between select in the I/O
> manager and the runtime. What is the difference? Should I just plug -
> threaded into my cabal file and not worry about it? How big of an
> impact is select() in the runtime?

When the runtime is doing select(), you'll get more calls to select()
because the runtime calls it for every thread switch, whereas with
-threaded select() is only called when something changes - we need to
wait on a new descriptor, or I/O is available on one or more
descriptors.  So you should get better performance with -threaded for
large numbers of descriptors.  Also you might get a small amount of
parallelism on a multi-processor because the select() will run on a
different CPU.

I'm aware that there are various better alternatives to select(), but we
don't use any of them yet.

Cheers,
        Simon
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe