This post is sponsored by forkIO
function and newChan
in Haskell
What is this forkIO ?
forkIO is part of Control.Concurrent
package and as it says it:
Sparks off a new thread to run the IO computation passed as the first argument, and returns the ThreadId of the newly created thread. The new thread will be a lightweight thread; if you want to use a foreign library that uses thread-local storage, use forkOS instead.
This is very neat if your program wants to use all the cores of your CPU or at least be more responsive not waiting for stuff to happen.
forkIO type is:
1
|
|
Channels to help !
forkIO would be enough to start working on stuff but to make a real use of them we need a way of communicating with our threads. This actually opens design of our code to new stuff like building workers. There are other ways of communicating with threads like mVar but IMHO channels win hard.
Channels are part of Control.Concurrent.Chan
package and are typable! Typed communication Yay!
Channels functions we need have the following type signatures:
1 2 3 |
|
And that’s actually all we need. Let’s make some stuff working.
Ok So lets get this party started :)
I think most of the time it’s better to explain stuff on examples.
Just spawn!
First thing we want is just to spawn!
1 2 3 4 5 6 |
|
This is a very simple way to spawn a light weight thread via forkIO :>. As you can see it is a normal action so you can go dirty!
forkIO takes actions and give you back IO ThreadId so you can keep track / kill threads you don’t like
Just Spawn
Previous example was a bit cheating as it showed nothing really important so lets make some crazy threads printing stuff now.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Well compiling and running this gives you only “hit it guys” as main thread exits and child threads dies! lets fix it so we can say when they need to stop!:>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
After launching it you can see how each thread is spamming its prints ;> So it work until you will hit enter. Cool so we have something working.
How does it work ? first of all we use forkIO to spawn threads and this time we have each “thread” function in separation.
Each of them run forever like crazy music fans :). In this place we can make it simple by using forever
from Control.Monad
to make it simpler.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
forever
is part of Control.Monad
as name says it is doing action forever ;) useful for stuff like workers or stuff that has to happen all the time it type is forever :: Monad m => m a -> m b
.
Something useful, add channels
Cool so now we have some basics how to spawn a thread using forkIO but to have something that we actually can use in real life we need to have some sort of communication. I wanna present something i feel would be useful in almost every haskell program. Channel combined with forkIO.
If you programmed ever in Erlang
or Go
you will know what i’m talking about, channels are very similar to message passing. Basically it is a pipe that you can write to or read from in different threads/processes. This is one of the mechanism we can use to get data out of other threads. Because they are not sequential we can’t predict normal vals or time when they will be ready. One of the ways of getting response from threads are channels.
Channels are amazing because they are flexible :) And very natural. Basic principle is simple you write in one thread to the channel and read in other :)
But lets make an example that will show how powerful it is.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Nice! What happens here :) So new things are newChan
that create channel which we will use to talk to our gossipGirl. readChan
reads data from channel and writeChan
writes stuff to channel. This is very simple :) So now lets generalize our worker into something that we can use in next mini tutorials. A worker.
A Worker
simple worker will take 1 channel as parameter and spawn thread this will help us in understanding how this whole thing works. (ofc if we don’t got it by now :) )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Yes you can build workers as you want. I would not spend time on trying to build uber generic worker as it is usually custom and you don’t need to spend much time to make one :). Usually you can have worker types for particular tasks eg. databasesWriter, logWriters, counters etc.
Now why would you all this forkIO stuff ? here is there reason. Cat simulation!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Summary
I hope this gives a little insight into forkIO
and channels
functions as You should use them in your code. It is super simple to add them, they work miracles and i love them. Yes you don’t need to be expert on Kleisli arrows to use them ;).
Cheers!