Proposal: Control.Concurrent.Async

Simon Marlow marlowsd at gmail.com
Fri Jun 15 10:07:54 CEST 2012


On 14/06/2012 13:12, Sjoerd Visscher wrote:
> On Thu, 14 Jun 2012 12:42:51 0100, Simon Marlow <marlowsd at gmail.com> wrote:
> On 13/06/2012 22:58, Sjoerd Visscher wrote:
>  > > (page1, page2, page3)
>> > <- runConcurrently $ (,,)
>> > <$> Concurrently (getURL "url1")
>> > <*> Concurrently (getURL "url2")
>> > <*> Concurrently (getURL "url3")
>> >
>> > More code here: https://gist.github.com/2926572
>>
>> I'm not sure about this. What you get with the above code is a strange
>> nesting of concurrently calls, whereas what the user might expect is
>> for it to behave like the existing concurrently but on 3-tuples
>> instead of pairs.
>
> Actually, that is what I expected too. So, this is not the way to use
> concurrently?
>
> concurrently3 m1 m2 m3 = (((v1, v2), v3) -> (v1, v2, v3)) <$>
>    concurrently (concurrently m1 m2) m3

So what bothered me about this is that it makes 4 threads when I would 
expect 3, and also the asymmetry looks strange.  However see below.

> or does it have to be:
>
> wait3 a1 a2 a3 =
>    atomically $ do
>      v1 <- waitSTM a1 `orElse` (waitSTM a2 >> waitSTM a3 >> retry)
>      v2 <- waitSTM a2 `orElse` (waitSTM a3 >> retry)
>      v3 <- waitSTM a3
>      return (v1, v2, v3)

I had in mind this:

waitList :: [Async a] -> IO [a]
waitList xs = atomically $ do
   foldr orElse retry (map (void.waitSTM) xs)
   mapM waitSTM xs

but, the problem is that this is an O(N)-sized transaction and it will 
be run O(N) times before it commits, giving us O(N^2).

I've just tested it and it scales terribly, the nested version is much 
better.  So that's an interesting discovery!

I still need to ponder the Applicative version, I'm not familiar with 
Control.Newtype.  I would still like the Traversable abstraction I 
mentioned in my last message.

Cheers,
	Simon



More information about the Libraries mailing list