
Hi folks. Take a look at this: render :: IOArray Point Colour -> (Point -> Colour) -> IO () render framebuffer fn = mapM_ (\p -> writeArray framebuffer p (fn p)) all_points How do I alter this to compute fn in multiple threads in parallel? (As you can see from the type signature, the calculation is independent for each pixel.) Thanks.

On Mon, 2007-11-05 at 20:12 +0000, Andrew Coppin wrote:
Hi folks.
Take a look at this:
render :: IOArray Point Colour -> (Point -> Colour) -> IO () render framebuffer fn = mapM_ (\p -> writeArray framebuffer p (fn p)) all_points
How do I alter this to compute fn in multiple threads in parallel? (As you can see from the type signature, the calculation is independent for each pixel.)
You can spark a thread for each computation of fn, like such: writeArray framebuffer p `parApp` fn p where parApp f x = x `par` f x Or, alternatively, since I believe IOArray is lazy, you could grab a list and hand it to parListChunk (from Parallel.Strategies) or there abouts: xn <- getElems framebuffer evaluate $ parListChunk 100 rwhnf or something (evaluate is from Control.Exception; rwhnf is also from Parallel.Strategies). jcc

Jonathan Cast wrote:
On Mon, 2007-11-05 at 20:12 +0000, Andrew Coppin wrote:
Hi folks.
Take a look at this:
render :: IOArray Point Colour -> (Point -> Colour) -> IO () render framebuffer fn = mapM_ (\p -> writeArray framebuffer p (fn p)) all_points
How do I alter this to compute fn in multiple threads in parallel? (As you can see from the type signature, the calculation is independent for each pixel.)
You can spark a thread for each computation of fn, like such:
writeArray framebuffer p `parApp` fn p where parApp f x = x `par` f x
Hmm, that may be a little *too* fine-grained. (But then, just because I spark 175,862 threads doesn't mean it will actually *run* that many at once, right?) I guess I'll try it and see...
Or, alternatively, since I believe IOArray is lazy, you could grab a list and hand it to parListChunk (from Parallel.Strategies) or there abouts:
xn <- getElems framebuffer evaluate $ parListChunk 100 rwhnf
or something (evaluate is from Control.Exception; rwhnf is also from Parallel.Strategies).
Yes, IOArray is lazy. The *real* array type I'm using is unboxed and therefore strict - however, the order in which pixels are written is of no interest to me. I will sit and have a think about this one too. Thanks.

On Nov 5, 2007, at 15:46 , Andrew Coppin wrote:
You can spark a thread for each computation of fn, like such:
writeArray framebuffer p `parApp` fn p where parApp f x = x `par` f x
Hmm, that may be a little *too* fine-grained. (But then, just because I spark 175,862 threads doesn't mean it will actually *run* that many at once, right?) I guess I'll try it and see...
As I understand it, the GHC "spark" implementation is specifically designed to support the case of making lots of sparks and letting the runtime schedule them to threads. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

Hello Andrew, Monday, November 5, 2007, 11:12:33 PM, you wrote:
How do I alter this to compute fn in multiple threads in parallel? (As
jobs :: [IO()] let fork job = do mvar <- newEmptyMVar forkIO$ do job; putMVar mvar () return mvar tasks <- mapM fork jobs mapM_ takeMVar tasks these runs jobs and waits before all them will be finished -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Is it possible to use the forkIO primitive to cause pure computations to be evaluated in parallel threads? It seems to me that laziness would always prevent any evaluation until the result was used in a consuming thread (and hence would occur serially, in that thread). Tim -----Original Message----- From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Bulat Ziganshin Sent: Tuesday, 6 November 2007 10:59 AM To: Andrew Coppin Cc: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] Go parallel Hello Andrew, Monday, November 5, 2007, 11:12:33 PM, you wrote:
How do I alter this to compute fn in multiple threads in parallel? (As
jobs :: [IO()] let fork job = do mvar <- newEmptyMVar forkIO$ do job; putMVar mvar () return mvar tasks <- mapM fork jobs mapM_ takeMVar tasks these runs jobs and waits before all them will be finished -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

timd:
Is it possible to use the forkIO primitive to cause pure computations to be evaluated in parallel threads?
It seems to me that laziness would always prevent any evaluation until the result was used in a consuming thread (and hence would occur serially, in that thread).
Try `par` and friends in Control.Parallel. You can also build referentially transparent worker gangs on top of forkIO. -- Don

Thanks - I was aware of par and it's ilk, but I couldn't imagine any way of doing the latter... how can you actually force something pure to get calculated in a worker thread? But thinking now, I guess judicious use of seq or deepseq is appropriate. Something like this might work. workerThread :: (a->b) -> MVar a -> MVar b -> IO () workerThread f inp out = do a <- takeMVar inp let b = f a in (b `seq` putMVar out b) workerThread f inp out In a spare moment I'll have to give it a go. Tim -----Original Message----- From: Don Stewart [mailto:dons@galois.com] Sent: Tuesday, 6 November 2007 11:16 AM To: Tim Docker Cc: haskell-cafe@haskell.org; Bulat Ziganshin Subject: Re: [Haskell-cafe] Go parallel timd:
Is it possible to use the forkIO primitive to cause pure computations to be evaluated in parallel threads?
It seems to me that laziness would always prevent any evaluation until
the result was used in a consuming thread (and hence would occur serially, in that thread).
Try `par` and friends in Control.Parallel. You can also build referentially transparent worker gangs on top of forkIO. -- Don

Hello Tim, Tuesday, November 6, 2007, 3:13:05 AM, you wrote:
Is it possible to use the forkIO primitive to cause pure computations to be evaluated in parallel threads?
It seems to me that laziness would always prevent any evaluation until the result was used in a consuming thread (and hence would occur serially, in that thread).
yes, that's true. but we can force evaluation of array elements: task (i,j) = do putArray arr (i,j) (i*j) return $! getArray arr (i,j) in the Andrew's case, array in unboxed, so putArray will evaluate its argument without additional return$! on the other side, he can use boxed immutable array and use tasks exactly to enforce evaluation of lazy boxes: let arr = array (0,0) (10,10) [i*j | i<-0..10, j<-0..10] let task (i,j) = return $! elemArray arr (i,j) -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Hello Bulat, Tuesday, November 6, 2007, 3:43:30 AM, you wrote:
yes, that's true. but we can force evaluation of array elements:
task (i,j) = do putArray arr (i,j) (i*j) return $! getArray arr (i,j)
correct way: task (i,j) = do putArray arr (i,j) $! (i*j) this forces evaluation before writing value to array. not required for unboxed arrays -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Tim Docker wrote:
Is it possible to use the forkIO primitive to cause pure computations to be evaluated in parallel threads?
Somebody correct me here - I was under the impression that you only ever need forkIO if you're doing something strange with FFI, and usually you just want fork?

Am Dienstag, 6. November 2007 schrieb Andrew Coppin:
Somebody correct me here - I was under the impression that you only ever need forkIO if you're doing something strange with FFI, and usually you just want fork?
You're probably thinking of forkOS vs. forkIO. AFAIK there is no fork in Haskell.

andrewcoppin:
Tim Docker wrote:
Is it possible to use the forkIO primitive to cause pure computations to be evaluated in parallel threads?
Somebody correct me here - I was under the impression that you only ever need forkIO if you're doing something strange with FFI, and usually you just want fork?
That's incorrect. forkIO is *the* basic threading primitive for fast, light Haskell threads. You might be thinking of 'forkOS' -- that's for weird FFI strangeness. -- Don

Don Stewart wrote:
andrewcoppin:
Somebody correct me here - I was under the impression that you only ever need forkIO if you're doing something strange with FFI, and usually you just want fork?
That's incorrect. forkIO is *the* basic threading primitive for fast, light Haskell threads. You might be thinking of 'forkOS' -- that's for weird FFI strangeness.
Yeah, I think you're right. (Hmm... Is there even a function named just "fork"?)
participants (7)
-
Andrew Coppin
-
Brandon S. Allbery KF8NH
-
Bulat Ziganshin
-
Don Stewart
-
Jonathan Cast
-
Lukas Mai
-
Tim Docker