Proposal: Control.Concurrent.Async

I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose: http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht... In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course). One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether. Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync: withAsync :: IO a -> (Async a -> IO b) -> IO b the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already. I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too. Cheers, Simon

On Jun 8, 2012 11:37 AM, "Simon Marlow"
I'd like to add a higher-level concurrency API to the base package. This
API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async'
and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common
pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving
threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second
argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any
inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
What's the advantage to putting this in base instead of a separate package? If it goes in base, it will make it more difficult to upgrade, and take longer for this module to be adopted at all. If possible, I'd opt for a standalone package. Michael

On Fri, Jun 08, 2012 at 12:41:29PM +0300, Michael Snoyman wrote:
On Jun 8, 2012 11:37 AM, "Simon Marlow"
wrote: I'd like to add a higher-level concurrency API to the base package.
What's the advantage to putting this in base instead of a separate package? If it goes in base, it will make it more difficult to upgrade, and take longer for this module to be adopted at all. If possible, I'd opt for a standalone package.
I agree. This doesn't sound like it needs to be a package shipped with GHC, let alone in the base package. Thanks Ian

On 08/06/2012 10:41, Michael Snoyman wrote:
What's the advantage to putting this in base instead of a separate package? If it goes in base, it will make it more difficult to upgrade, and take longer for this module to be adopted at all. If possible, I'd opt for a standalone package.
Uploading it to Hackage is certainly an option, and there are arguments in both directions. My thinking was: - it's a bit small for a package by itself. There's a lot of overhead for a package (github repo, Haskell Platform proposal, issue tracker, blah blah) - To avoid further fragmentation, I would like this package to be more visible, especially if we go to the trouble as a community of building some consensus around it. - The obvious package name 'async' is already taken Cheers, Simon

On Jun 8, 2012 1:07 PM, "Simon Marlow"
On 08/06/2012 10:41, Michael Snoyman wrote:
What's the advantage to putting this in base instead of a separate package? If it goes in base, it will make it more difficult to upgrade, and take longer for this module to be adopted at all. If possible, I'd opt for a standalone package.
Uploading it to Hackage is certainly an option, and there are arguments
in both directions. My thinking was:
- it's a bit small for a package by itself. There's a lot of overhead for a package (github repo, Haskell Platform proposal, issue tracker, blah blah)
- To avoid further fragmentation, I would like this package to be more visible, especially if we go to the trouble as a community of building some consensus around it.
- The obvious package name 'async' is already taken
Cheers, Simon
Maybe we could address some of those issues: perhaps Peter Simons would be willing to forfeit the package name in favor of this updated one. That would provide more consolidation, and let the community-driven package use the obvious name. Michael

On 08/06/2012 11:29, Michael Snoyman wrote:
On Jun 8, 2012 1:07 PM, "Simon Marlow"
mailto:marlowsd@gmail.com> wrote: On 08/06/2012 10:41, Michael Snoyman wrote:
What's the advantage to putting this in base instead of a separate package? If it goes in base, it will make it more difficult to upgrade, and take longer for this module to be adopted at all. If possible, I'd opt for a standalone package.
Uploading it to Hackage is certainly an option, and there are
arguments in both directions. My thinking was:
- it's a bit small for a package by itself. There's a lot of overhead for a package (github repo, Haskell Platform proposal, issue tracker, blah blah)
- To avoid further fragmentation, I would like this package to be more visible, especially if we go to the trouble as a community of building some consensus around it.
- The obvious package name 'async' is already taken
Cheers, Simon
Maybe we could address some of those issues: perhaps Peter Simons would be willing to forfeit the package name in favor of this updated one. That would provide more consolidation, and let the community-driven package use the obvious name.
Peter let me know that he's happy for me to reuse the 'async' name. I've uploaded the code to github so people can play around with it and send me patches easily: https://github.com/simonmar/async Cheers, Simon

+1
What's the advantage to putting this in base instead of a separate
package? If it goes in base, it will make it more difficult to upgrade, and take longer for this module to be adopted at all. If possible, I'd opt for a standalone package.
I thought the idea was that we would try to point people towards using these as a best practice as opposed to using forkIO? I find that a helper function to fork a child thread with error handling is something I'm always pasting into various projects [1], which I take as a sign it should be easily available. I never really thought about looking for better threads packages on hackage, because I didn't want to add an extra dependency (or deal with something big and complex). But if it were standard I would have picked it up! -Ryan [1] P.S. Non-sequitor: The other little helper function I'm ALWAYS pasting into files is a function to print large numbers with interspersed commas. I'd like to see THAT in the standard ;-), but I realize there are internationalization issues.

On 8 June 2012 11:07, Simon Marlow
On 08/06/2012 10:41, Michael Snoyman wrote:
What's the advantage to putting this in base instead of a separate package? If it goes in base, it will make it more difficult to upgrade, and take longer for this module to be adopted at all. If possible, I'd opt for a standalone package.
Uploading it to Hackage is certainly an option, and there are arguments in both directions. My thinking was:
- it's a bit small for a package by itself. There's a lot of overhead for a package (github repo, Haskell Platform proposal, issue tracker, blah blah)
- To avoid further fragmentation, I would like this package to be more visible, especially if we go to the trouble as a community of building some consensus around it.
- The obvious package name 'async' is already taken
I am very much against putting things into base unless there is a *very* good argument to do this. If it is supposed to be *the* standard package, then it belongs into the platform, not base. If the platform process is too heavy-weight to discourage this path, then we need to do something about that rather than sneak things in through the base library. It already is a pain to work around issues in the base library (and many other core packages) since it's (a) takes a long time for an update to be released, and (b) cannot be upgraded independently from GHC (pulling in all the changes to other libraries as well). I'm glad that the name issues is resolved. If it is a small library a platform addition proposal shouldn't be too difficult either. We just have to beware of too much bike shedding. (BTW, have we had another platform proposal since the text package?)

Thomas Schilling wrote:
On 8 June 2012 11:07, Simon Marlow
wrote: Uploading it to Hackage is certainly an option, and there are arguments in both directions. My thinking was: [..] - it's a bit small for a package by itself. There's a lot of overhead for a package (github repo, Haskell Platform proposal, issue tracker, blah blah)
Github provides much of the infrastructure by default, like an issue tracker.
I am very much against putting things into base unless there is a *very* good argument to do this. If it is supposed to be *the* standard package, then it belongs into the platform, not base. If the platform process is too heavy-weight to discourage this path, then we need to do something about that rather than sneak things in through the base library. It already is a pain to work around issues in the base library (and many other core packages) since it's (a) takes a long time for an update to be released, and (b) cannot be upgraded independently from GHC (pulling in all the changes to other libraries as well).
I'm glad that the name issues is resolved. If it is a small library a platform addition proposal shouldn't be too difficult either. We just have to beware of too much bike shedding.
(BTW, have we had another platform proposal since the text package?)
+1 for a separate package that is included in the Haskell Platform. If merging a package into the base library is easier than the process of including it in the Haskell Platform, then the latter needs to be fixed. Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

Simon Marlow
- To avoid further fragmentation, I would like this package to be more visible, especially if we go to the trouble as a community of building some consensus around it.
...would it help to advertise the new `async` package in the appropriate places in the Haddoc documentation for `base` to make it more visible?

On 6/9/12 4:32 AM, Herbert Valerio Riedel wrote:
Simon Marlow
writes: - To avoid further fragmentation, I would like this package to be more visible, especially if we go to the trouble as a community of building some consensus around it.
...would it help to advertise the new `async` package in the appropriate places in the Haddoc documentation for `base` to make it more visible?
I wonder if it'd be worthwhile to have a "metabase package" which includes all the modules which are, used to be, or 'should' be in base. What I mean is not to have an actual package (in the ghc/hackage sense), but just to have a single unified Haddock site that covers and advertises all of: * base * the things broken out from base-3.0 (array, bytestring, containers, directory, old-locale, old-time, packedstring, pretty, process, random)--- modulo things like packedstring which have been deprecated. * things broken out from base-4.0 (syb,...) * things which 'should' be part of base (text? vector? async?) * but not including all of the HP Perhaps this already exists in an official incarnation somewhere, but if so then it's poorly advertised. The url should be listed in the description of the base package on Hackage, at the very least. -- Live well, ~wren

I fixed the docs a tiny bit in: https://github.com/simonmar/async/pull/1
Other comments:
- Module introduction is missing.
- There are no tests whatsoever. I would like to have a few stress
tests that throw lots of asynchronous exceptions to make sure that
exception masking etc behaves correctly.
- Why is there no waitAnyCancel?
- Same with waitEitherCancel
On 8 June 2012 09:37, Simon Marlow
I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Push the envelope. Watch it bend.

On 08/06/2012 17:31, Thomas Schilling wrote:
I fixed the docs a tiny bit in: https://github.com/simonmar/async/pull/1
Other comments:
- Module introduction is missing.
Now added.
- There are no tests whatsoever. I would like to have a few stress tests that throw lots of asynchronous exceptions to make sure that exception masking etc behaves correctly.
Also added, including a couple of stress tests. (but the test coverage isn't great, I'll try to improve it in due course)
- Why is there no waitAnyCancel? - Same with waitEitherCancel
Both added. I think that now addresses all the comments that people had. There's one more change I'm thinking about: perhaps instead of wait :: Async a -> IO (Either SomeException a) waitThrow :: Async a -> IO a we should reverse the naming scheme, rename waitThrow to wait and wait to something else (waitCatch?). Rationale: waitThrow seems to be the version we need most often, and it's simpler to use. wait :: Async a -> IO a waitCatch :: Async a -> IO (Either SomeException a) Thoughts? Better names for waitCatch? Latest Haddocks: http://community.haskell.org/~simonmar/async/ Repo: https://github.com/simonmar/async Cheers, Simon
On 8 June 2012 09:37, Simon Marlow
wrote: I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Tue, Jun 12, 2012 at 12:58 PM, Simon Marlow
I think that now addresses all the comments that people had.
There's one more change I'm thinking about: perhaps instead of
wait :: Async a -> IO (Either SomeException a) waitThrow :: Async a -> IO a
we should reverse the naming scheme, rename waitThrow to wait and wait to something else (waitCatch?). Rationale: waitThrow seems to be the version we need most often, and it's simpler to use.
wait :: Async a -> IO a waitCatch :: Async a -> IO (Either SomeException a)
Thoughts? Better names for waitCatch?
Latest Haddocks:
Two small ones: - In the documentation for cancel: "Has no effect if the Async has already", it seems like something might have been cut off. - Can we find a more accurate name for tryWait? It doesn't try and possibly fail to wait, it avoids waiting altogether. Maybe don'tWait, although that doesn't say what it does do. The only other idea I have is 'check' which is not very descriptive...
Repo:
https://github.com/simonmar/async
Cheers, Simon
On 8 June 2012 09:37, Simon Marlow
wrote: I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Work is punishment for failing to procrastinate effectively.

On 12/06/2012 12:38, Gábor Lehel wrote:
On Tue, Jun 12, 2012 at 12:58 PM, Simon Marlow
wrote: I think that now addresses all the comments that people had.
There's one more change I'm thinking about: perhaps instead of
wait :: Async a -> IO (Either SomeException a) waitThrow :: Async a -> IO a
we should reverse the naming scheme, rename waitThrow to wait and wait to something else (waitCatch?). Rationale: waitThrow seems to be the version we need most often, and it's simpler to use.
wait :: Async a -> IO a waitCatch :: Async a -> IO (Either SomeException a)
Thoughts? Better names for waitCatch?
Latest Haddocks:
Two small ones:
- In the documentation for cancel: "Has no effect if the Async has already", it seems like something might have been cut off.
- Can we find a more accurate name for tryWait? It doesn't try and possibly fail to wait, it avoids waiting altogether. Maybe don'tWait, although that doesn't say what it does do. The only other idea I have is 'check' which is not very descriptive...
Good point. How about "poll"? Cheers, Simon
Repo:
https://github.com/simonmar/async
Cheers, Simon
On 8 June 2012 09:37, Simon Marlow
wrote: I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Tue, Jun 12, 2012 at 2:26 PM, Simon Marlow
- Can we find a more accurate name for tryWait? It doesn't try and possibly fail to wait, it avoids waiting altogether. Maybe don'tWait, although that doesn't say what it does do. The only other idea I have is 'check' which is not very descriptive...
Good point. How about "poll"?
Definitely better.

On Tue, Jun 12, 2012 at 3:37 PM, Gábor Lehel
On Tue, Jun 12, 2012 at 2:26 PM, Simon Marlow
wrote: - Can we find a more accurate name for tryWait? It doesn't try and possibly fail to wait, it avoids waiting altogether. Maybe don'tWait, although that doesn't say what it does do. The only other idea I have is 'check' which is not very descriptive...
Good point. How about "poll"?
Definitely better.
Just ideas: - waitAny and company could be generalized to any Foldable. Downside: it makes the type signatures less obvious. Upside: if people will be taking the completed Async and removing it from the list (and doing this frequently), they might prefer something more efficient than a list. - If we want to follow the analogy, waitAny could be called 'select'.

On Tue, Jun 12, 2012 at 11:58:41AM +0100, Simon Marlow wrote:
There's one more change I'm thinking about: perhaps instead of
wait :: Async a -> IO (Either SomeException a) waitThrow :: Async a -> IO a
we should reverse the naming scheme, rename waitThrow to wait and wait to something else (waitCatch?). Rationale: waitThrow seems to be the version we need most often, and it's simpler to use.
wait :: Async a -> IO a waitCatch :: Async a -> IO (Either SomeException a)
Thoughts? Better names for waitCatch?
Perhaps the recently freed tryWait would be analogous with Control.Exception.try.

Your superset API is excellent. I have one important suggestions: non-blocking killThread. By default, when your combinators like 'withAsync' and 'concurrently' use 'cancel' or 'killThread' they should use it in a non-blocking way. The exported 'cancel' & 'cancelWith' should be unchanged and their documention should note that they are blocking. Consider 'concurrently'. Perhaps there need to to be two 'concurrently' versions? One is blocking-killThread and guarantees that both are done or dead when it returns and the other is non-blocking-killThread and returns ASAP. Neither can be turned into the other by the user. Rather than API duplication the 'concurrently' operation could get a new parameter that selects blocking vs non-blocking killThread. Hmmm.... the root problem is some Async tasks that, probably due to foreign calls, are uninterpretable. Maybe the user could label which Async tasks must be killed blocking or non-blocking. The default is non-blocking to avoid infecting other threads with uninterpretable calls. When the user needs the extra property of guaranteed kills the user can change the label. I have no immediate idea whether a mutable or immutable label would be better. -- Chris On 2012/06/08 09:37, Simon Marlow wrote:
I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On 09/06/2012 09:50, Chris Kuklewicz wrote:
Your superset API is excellent. I have one important suggestions: non-blocking killThread.
By default, when your combinators like 'withAsync' and 'concurrently' use 'cancel' or 'killThread' they should use it in a non-blocking way. The exported 'cancel'& 'cancelWith' should be unchanged and their documention should note that they are blocking.
Consider 'concurrently'. Perhaps there need to to be two 'concurrently' versions? One is blocking-killThread and guarantees that both are done or dead when it returns and the other is non-blocking-killThread and returns ASAP. Neither can be turned into the other by the user.
Rather than API duplication the 'concurrently' operation could get a new parameter that selects blocking vs non-blocking killThread.
Hmmm.... the root problem is some Async tasks that, probably due to foreign calls, are uninterpretable. Maybe the user could label which Async tasks must be killed blocking or non-blocking. The default is non-blocking to avoid infecting other threads with uninterpretable calls. When the user needs the extra property of guaranteed kills the user can change the label. I have no immediate idea whether a mutable or immutable label would be better.
I appreciate that sometimes cancel may block and that you may want a non-blocking cancel, but I don't think that should be the default. Firstly, the user might find it surprising if when withAsync has returned, the Async still performs some more operations (that are not inside an exception handler). I think it's an important guarantee that this doesn't happen - otherwise, what can you say with any certainty about the behaviour of withAsync? Secondly, asynchronous cancel is easily implemented by the user, as asyncCancel = async . cancel what a lovely definition :-) We even get to decide later on to wait for the cancel to happen, by waiting on the result of asyncCancel, and we can cancel the asyncCancel itself. Thirdly, asynchronous cancel is less efficient than synchronous cancel, because it involves forking a new thread. I will document carefully that we are using the synchronous cancel and the implications of that, and I'll add asyncCancel. Cheers, Simon

I think we should distinguish two cases for "cancel". I emphasized one case and rambled a bit in my previous message. I hope this is clearer. On 2012/06/12 11:33, Simon Marlow wrote:
I appreciate that sometimes cancel may block and that you may want a non-blocking cancel, but I don't think that should be the default.
Firstly, the user might find it surprising if when withAsync has returned, the Async still performs some more operations (that are not inside an exception handler). I think it's an important guarantee that this doesn't happen - otherwise, what can you say with any certainty about the behaviour of withAsync?
I totally 100% have always agreed with that -- for withAsync. That is the correct semantics to minimize surprise when sequencing the two IO actions. But... you also include "race" and "concurrently" where the user has explicitly asked to go crazy with lots of non-deterministic interleaving. It may be that some are talking to blocking FFI things and thus it may be nice to have a version of these that calls asyncCancel internally:
Secondly, asynchronous cancel is easily implemented by the user, as
asyncCancel = async . cancel
If a user wanted race + asyncCancel then she could copy-paste your module's code with the changes. This is certainly something the user could do -- and the documentation can point out when it would be needed. I hope I have been clearer. I was not being crazy and says withAsync needed asyncCancel. -- Chris

Hello,
A nice library, I've had to re-implement similar functionality, so this
would be useful!
Some questions about the waiting combinators:
1. I was expecting that `waitAny` and friends, would also return the result
of the first computation that completed. Is there a reason not to do so?
2. Is `waitAny` waiting for one of the Asyncs to complete _successfully_ or
is throwing an exception considered as completion? I am guessing the
former, with `waitAnyThrow` providing the latter functionality?
3. As far as I understand, `waitAny` does not stop the other asyncs (it'd
be nice to add this note to its documentation, explicitly). If that's the
case, perhaps it's type should be: `waitAny :: [Async a] -> IO (a,[Async
a])`, so that we can keep on waiting for more asyncs, if needed?
-Iavor
On Fri, Jun 8, 2012 at 1:37 AM, Simon Marlow
I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~**simonmar/async-stm/Control-** Concurrent-Async.htmlhttp://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
______________________________**_________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/**mailman/listinfo/librarieshttp://www.haskell.org/mailman/listinfo/libraries

On 09/06/12 17:50, Iavor Diatchki wrote:
Hello, A nice library, I've had to re-implement similar functionality, so this would be useful!
Some questions about the waiting combinators:
1. I was expecting that `waitAny` and friends, would also return the result of the first computation that completed. Is there a reason not to do so? 2. Is `waitAny` waiting for one of the Asyncs to complete _successfully_ or is throwing an exception considered as completion? I am guessing the former, with `waitAnyThrow` providing the latter functionality? 3. As far as I understand, `waitAny` does not stop the other asyncs (it'd be nice to add this note to its documentation, explicitly). If that's the case, perhaps it's type should be: `waitAny :: [Async a] -> IO (a,[Async a])`, so that we can keep on waiting for more asyncs, if needed?
All good points. I don't have many use cases for the waitAny* family yet so I'd been holding off refining the API until I had a clearer picture of what would be useful for clients. There are lots of possibilities here. But in light of your comments I have changed the type of waitAny to this: waitAny :: [Async a] -> IO (Async a, Either SomeException a) so that it now returns both the Async that completed and its result. Since Async supports Eq, the caller can remove the completed one from the list and call waitAny again if necessary. Similarly waitAnyThrow now has this type: waitAnyThrow :: [Async a] -> IO (Async a, a) I've also added a non-blocking wait: tryWait :: Async a -> IO (Maybe (Either SomeException a)) so that after a waitAny the caller can check all of the Asyncs for completion and remove multiple completed Asyncs from the list. Latest Haddocks here: http://community.haskell.org/~simonmar/async/ Cheers, Simon
-Iavor
On Fri, Jun 8, 2012 at 1:37 AM, Simon Marlow
mailto:marlowsd@gmail.com> wrote: I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~__simonmar/async-stm/Control-__Concurrent-Asyn... http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_________________________________________________ Libraries mailing list Libraries@haskell.org mailto:Libraries@haskell.org http://www.haskell.org/__mailman/listinfo/libraries http://www.haskell.org/mailman/listinfo/libraries

On 6/9/12 5:28 PM, Simon Marlow wrote:
All good points. I don't have many use cases for the waitAny* family yet so I'd been holding off refining the API until I had a clearer picture of what would be useful for clients. There are lots of possibilities here.
The way I typically use it is as follows: The main thread spawns off a bunch of heterogeneous workers--- the kind that interact with one another in an event-loop like manner (not of the fire-and-forget nor the web-server kind). But, the workers may fail/terminate for various reasons--- including thrown exceptions, but also more benign things like expected failure modes (encoded in normal ADTs or passed along via TChans/TVars/etc), and temporary failures that just require some 'manual' help to get unstuck. After firing them off to do the work, the main thread's job is to monitor the workers in order to (a) handle any of the failure modes it can, (b) ensure clean and safe shutdown in the event of irrecoverable errors. A related but somewhat different style of using waitAny* parallelism is for things like grid managers. Again, there are a bunch of heterogeneous worker threads. But this time, rather than focusing on errorful termination as above, the focus here is on proper termination. In particular, once some job A has finished, we can now start jobs B, C, and D which depend on the output of A. In the small scale, you can just have A finish by firing off the other jobs; but in the large scale that doesn't work. You need to (a) be able to specify the job dependencies independently of the work that job is doing, (b) be able to handle failures and restarts as above, (c) perform load balancing[1], and so on. [1] For a proper grid manager this is "real" load balancing by deciding which machines a particular job should be run on. But even within a single OS process, we can know that certain tasks require more or less memory or other resources, and so can alter how aggressively to fire off jobs in order to keep from overloading the machine. It's this extreme heterogeneity of jobs which is a core part of being a "grid manager" IMO; when the jobs are relatively homogeneous (even if doing different things) then a lot of these complications go away. -- Live well, ~wren

2012/6/8, Simon Marlow
I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Hello, Simon. I have noticed that the computation strategy plays a role for the 'async' function. For example: asyncWaitCatch :: Int -> Int -> IO (Either String Int) asyncWaitCatch m n = async (return $ m `div` n) >>= waitCatch >>= return . either (const $ Left "divide by zero") Right gives -- > asyncWaitCatch 4 2 -- Right 2 -- > asyncWaitCatch 1 0 -- Right *** Exception: divide by zero but asyncWaitCatch :: Int -> Int -> IO (Either String Int) asyncWaitCatch m n = async (return $! m `div` n) >>= waitCatch >>= return . either (const $ Left "divide by zero") Right gives -- > asyncWaitCatch 4 2 -- Right 2 -- > asyncWaitCatch 1 0 -- Left "divide by zero" as expected. Also, in this kind of a higher-level interface, I would like to have some form of message passing. It can be done with STM channels, for example (I wrote a wrapper around threads and STM channels some times ago, here is how it looks - https://github.com/treep/hactors/blob/master/Control/Concurrent/Actor.hs).

Hi Simon, This a really nice and clean library! I was wondering if it would be useful to have an applicative interface for the concurrently function? Something like this: (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3") More code here: https://gist.github.com/2926572 Thanks, Sjoerd On Jun 8, 2012, at 10:37 AM, Simon Marlow wrote:
I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Sjoerd Visscher https://github.com/sjoerdvisscher/blog

On 13/06/2012 22:58, Sjoerd Visscher wrote:
Hi Simon,
This a really nice and clean library!
I was wondering if it would be useful to have an applicative interface for the concurrently function? Something like this:
(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. I like the idea of generalising to arbitrary Traversable structures though. Maybe we could provide something like doConcurrently :: Traversable t => t (IO a) -> IO (t a) I haven't tried to write it, but it looks like it ought to be possible. Cheers, Simon
Thanks, Sjoerd
On Jun 8, 2012, at 10:37 AM, Simon Marlow wrote:
I'd like to add a higher-level concurrency API to the base package. This API has grown while I've been working on examples for my book, and I'm convinced that we should have something like this in the standard libraries. Here's the API I propose:
http://community.haskell.org/~simonmar/async-stm/Control-Concurrent-Async.ht...
In fact it already exists in at least two packages on Hackage: 'async' and 'threads'. My version is a superset of both of these, except for a few small differences (which are up for discussion, of course).
One good reason to have this package is that it avoids some common pitfalls, such as forgetting to handle exceptions in your child threads. In the Async API, you get to choose whether to (a) receive the result as 'Either SomeException a', or (b) have the exception re-thrown in the waiting thread. You don't get to ignore it altogether.
Another common pitfall avoided by this library is accidentally leaving threads running in the background. This is handled by withAsync:
withAsync :: IO a -> (Async a -> IO b) -> IO b
the child thread is always cancelled (i.e. killed) when the second argument returns or throws an exception, if it hasn't finished already.
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
Cheers, Simon
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Sjoerd Visscher https://github.com/sjoerdvisscher/blog

On Fri, Jun 08, 2012 at 09:37:16AM +0100, Simon Marlow wrote:
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
I'd expect the arguments of cancelWith to be the other way round. Then you could say cancel = cancelWith ThreadKilled An alternative, equivalent interface for waitEither and friends would be waitEither :: Async a -> Async a -> IO (Either SomeException a) waitEitherThrow :: Async a -> Async a -> IO a This might be conceptually simpler, leaving it to the user to decide whether to mark the results with Left/Right, or something else, or not. Similarly the Async now returned by waitAny and friends could be left to the user. That would leave the two sets of functions more in line.

On 14/06/2012 16:10, Ross Paterson wrote:
On Fri, Jun 08, 2012 at 09:37:16AM +0100, Simon Marlow wrote:
I'm opening this up for discussion so that we can tidy up any inconsistent details and add any functions that people feel are missing. Naming is obviously up for discussion too.
I'd expect the arguments of cancelWith to be the other way round. Then you could say
cancel = cancelWith ThreadKilled
Agreed.
An alternative, equivalent interface for waitEither and friends would be
waitEither :: Async a -> Async a -> IO (Either SomeException a) waitEitherThrow :: Async a -> Async a -> IO a
This might be conceptually simpler, leaving it to the user to decide whether to mark the results with Left/Right, or something else, or not. Similarly the Async now returned by waitAny and friends could be left to the user. That would leave the two sets of functions more in line.
I liked this suggestion at first, but later concluded that it isn't as nice. The problem is that to convert an 'Async a' to an 'Async (Either a b)' has to be done when you create the Async in the first place, or else you have to write some STM code to lift the result. If you're writing some STM code anyway, then there's little point in using waitEither. So I think the waitEither and waitAny families complement each other; waitEither handles the lifting of the results into Either for you, which is sometimes handy. Cheers, Simon

On Fri, Jun 15, 2012 at 02:26:51PM +0100, Simon Marlow wrote:
On 14/06/2012 16:10, Ross Paterson wrote:
An alternative, equivalent interface for waitEither and friends would be
waitEither :: Async a -> Async a -> IO (Either SomeException a) waitEitherThrow :: Async a -> Async a -> IO a
This might be conceptually simpler, leaving it to the user to decide whether to mark the results with Left/Right, or something else, or not. Similarly the Async now returned by waitAny and friends could be left to the user. That would leave the two sets of functions more in line.
I liked this suggestion at first, but later concluded that it isn't as nice. The problem is that to convert an 'Async a' to an 'Async (Either a b)' has to be done when you create the Async in the first place, or else you have to write some STM code to lift the result. If you're writing some STM code anyway, then there's little point in using waitEither.
The list functions have a similar issue: you have to give them the right type when you create them if you want them together in a list. Perhaps a convenient interface for the multiplexing part would be data AsyncF a = forall r. AsyncF (Async r) (r -> a) instance Functor AsyncF where fmap f (AsyncF a k) = AsyncF a (f . k) waitSTMF :: AsyncF a -> STM (Either SomeException a) waitSTMF (AsyncF a k) = fmap (fmap k) (waitSTM a)

On 18/06/2012 14:56, Ross Paterson wrote:
On Fri, Jun 15, 2012 at 02:26:51PM +0100, Simon Marlow wrote:
On 14/06/2012 16:10, Ross Paterson wrote:
An alternative, equivalent interface for waitEither and friends would be
waitEither :: Async a -> Async a -> IO (Either SomeException a) waitEitherThrow :: Async a -> Async a -> IO a
This might be conceptually simpler, leaving it to the user to decide whether to mark the results with Left/Right, or something else, or not. Similarly the Async now returned by waitAny and friends could be left to the user. That would leave the two sets of functions more in line.
I liked this suggestion at first, but later concluded that it isn't as nice. The problem is that to convert an 'Async a' to an 'Async (Either a b)' has to be done when you create the Async in the first place, or else you have to write some STM code to lift the result. If you're writing some STM code anyway, then there's little point in using waitEither.
The list functions have a similar issue: you have to give them the right type when you create them if you want them together in a list. Perhaps a convenient interface for the multiplexing part would be
data AsyncF a = forall r. AsyncF (Async r) (r -> a)
instance Functor AsyncF where fmap f (AsyncF a k) = AsyncF a (f . k)
waitSTMF :: AsyncF a -> STM (Either SomeException a) waitSTMF (AsyncF a k) = fmap (fmap k) (waitSTM a)
Good idea. In fact, I've added a Functor instance for Async itself - it required a bit of refactoring but didn't add much overhead. Cheers, Simon

On Tue, Jul 03, 2012 at 01:53:16PM +0100, Simon Marlow wrote:
On 18/06/2012 14:56, Ross Paterson wrote:
Perhaps a convenient interface for the multiplexing part would be
data AsyncF a = forall r. AsyncF (Async r) (r -> a)
instance Functor AsyncF where fmap f (AsyncF a k) = AsyncF a (f . k)
waitSTMF :: AsyncF a -> STM (Either SomeException a) waitSTMF (AsyncF a k) = fmap (fmap k) (waitSTM a)
Good idea. In fact, I've added a Functor instance for Async itself - it required a bit of refactoring but didn't add much overhead.
So now you can simplify the interfaces of waitEither/waitAny et al? [BTW, could you generate the new docs with --hyperlink-source?]

On Tue, Jul 03, 2012 at 02:17:46PM +0100, Ross Paterson wrote:
On Tue, Jul 03, 2012 at 01:53:16PM +0100, Simon Marlow wrote:
Good idea. In fact, I've added a Functor instance for Async itself - it required a bit of refactoring but didn't add much overhead.
So now you can simplify the interfaces of waitEither/waitAny et al?
Ah, that won't work with the Catch versions.

On 03/07/2012 14:17, Ross Paterson wrote:
On Tue, Jul 03, 2012 at 01:53:16PM +0100, Simon Marlow wrote:
On 18/06/2012 14:56, Ross Paterson wrote:
Perhaps a convenient interface for the multiplexing part would be
data AsyncF a = forall r. AsyncF (Async r) (r -> a)
instance Functor AsyncF where fmap f (AsyncF a k) = AsyncF a (f . k)
waitSTMF :: AsyncF a -> STM (Either SomeException a) waitSTMF (AsyncF a k) = fmap (fmap k) (waitSTM a)
Good idea. In fact, I've added a Functor instance for Async itself - it required a bit of refactoring but didn't add much overhead.
So now you can simplify the interfaces of waitEither/waitAny et al?
[BTW, could you generate the new docs with --hyperlink-source?]
Hackage has the docs now: http://hackage.haskell.org/packages/archive/async/2.0.1.0/doc/html/Control-C... Cheers, Simon

On Wed, Jul 4, 2012 at 12:44 PM, Simon Marlow
Hackage has the docs now:
http://hackage.haskell.org/packages/archive/async/2.0.1.0/doc/html/Control-C...
Cheers, Simon
Perhaps it might make sense to reduce the duplication among the asyncOn/WithUnmask/etc. variants using an ADT? e.g. type Unmask a = (forall b. IO b -> IO b) -> IO a data Fork a = ForkIO (IO a) | ForkOS (IO a) | ForkOn Int (IO a) | ForkIOWithUnmask (Unmask a) | ForkOnWithUnmask Int (Unmask a) async :: IO a -> IO (Async a) asyncUsingFork :: Fork a -> IO (Async a) withAsync :: IO a -> (Async a -> IO b) -> IO b withAsyncUsingFork :: Fork a -> (Async a -> IO b) -> IO b (Didn't put much thought into names.) -- Your ship was caught in a monadic eruption. Game over.

Hi all, Since this thread has been quiet for a while, I'd like to make a call for any outstanding issues for the proposal to add the async package (in anticipation for a call for consensus if there aren't any.) Are there any outstanding issues? Cheers, Johan

Quoting "Simon Marlow"
Naming is obviously up for discussion too.
I feel that "Async" is a bit too generic and doesn't very precisely characterize this particular construct. How about "Future", as similar things are called in e.g. Alice http://www.ps.uni-saarland.de/alice/manual/futures.html and Java http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/FutureTask.htm...? Lauri

On 14/06/2012 22:54, Lauri Alanko wrote:
Quoting "Simon Marlow"
: Naming is obviously up for discussion too.
I feel that "Async" is a bit too generic and doesn't very precisely characterize this particular construct. How about "Future", as similar things are called in e.g. Alice http://www.ps.uni-saarland.de/alice/manual/futures.html and Java http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/FutureTask.htm...?
"Future" evokes notions of parallelism for me, rather than concurrency. I think the term is more often used in a parallel setting. There's a precedent for using 'async' for concurrency: see the new C# and F# async extensions: http://msdn.microsoft.com/en-us/library/hh191443%28v=vs.110%29.aspx But naming is hard, and if everyone wanted to use "future" instead I wouldn't object very strongly. Cheers, Simon

On 6/15/12 9:31 AM, Simon Marlow wrote:
On 14/06/2012 22:54, Lauri Alanko wrote:
Quoting "Simon Marlow"
: Naming is obviously up for discussion too.
I feel that "Async" is a bit too generic and doesn't very precisely characterize this particular construct. How about "Future", as similar things are called in e.g. Alice http://www.ps.uni-saarland.de/alice/manual/futures.html and Java http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/FutureTask.htm...?
"Future" evokes notions of parallelism for me, rather than concurrency. I think the term is more often used in a parallel setting.
There's a precedent for using 'async' for concurrency: see the new C# and F# async extensions:
http://msdn.microsoft.com/en-us/library/hh191443%28v=vs.110%29.aspx
But naming is hard, and if everyone wanted to use "future" instead I wouldn't object very strongly.
I object to "future" as using an overly general term for one very particular instantiation of it. At the very least it must be qualified as "concurrent future". Though I'm not particularly opposed to "async"; and if there's precedent, then all the better. -- Live well, ~wren

On 16 June 2012 13:26, wren ng thornton
On 6/15/12 9:31 AM, Simon Marlow wrote:
On 14/06/2012 22:54, Lauri Alanko wrote:
Quoting "Simon Marlow"
: Naming is obviously up for discussion too.
I feel that "Async" is a bit too generic and doesn't very precisely characterize this particular construct. How about "Future", as similar things are called in e.g. Alice http://www.ps.uni-saarland.de/alice/manual/futures.html and Java
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/FutureTask.htm...?
"Future" evokes notions of parallelism for me, rather than concurrency. I think the term is more often used in a parallel setting.
There's a precedent for using 'async' for concurrency: see the new C# and F# async extensions:
http://msdn.microsoft.com/en-us/library/hh191443%28v=vs.110%29.aspx
But naming is hard, and if everyone wanted to use "future" instead I wouldn't object very strongly.
I object to "future" as using an overly general term for one very particular instantiation of it. At the very least it must be qualified as "concurrent future". Though I'm not particularly opposed to "async"; and if there's precedent, then all the better.
"future" also seems to me to be more about waiting for the result value, not about doing something concurrently. Then again I work on a codebase which involves financial futures contracts, which also involve waiting for a return value ... Conrad.

On 6/14/12 5:54 PM, Lauri Alanko wrote:
Quoting "Simon Marlow"
: Naming is obviously up for discussion too.
I feel that "Async" is a bit too generic and doesn't very precisely characterize this particular construct. How about "Future", as similar things are called in e.g. Alice http://www.ps.uni-saarland.de/alice/manual/futures.html and Java http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/FutureTask.htm...?
"Future" is a generic term for a particular way of thinking about the life cycle of variables (both in AliceML, Mozart/Oz, and in the literature). From this perspective *all* variables are futures. For example, in the AliceML url you provide, they specifically qualify the different kinds of futures: * concurrent futures --- something like Async * lazy futures --- what Haskell has by default * promised futures --- for tying the knot; akin to "static" in Java * immediate futures (not mentioned on the AliceML page) --- the standard all-at-once way of introducing, binding, and evaluating variables. Of course, the concurrent/lazy/promised qualifiers can be combined since they define orthogonal axes of temporal distinction. -- Live well, ~wren

On 6/16/12 1:24 AM, wren ng thornton wrote:
"Future" is a generic term for a particular way of thinking about the life cycle of variables (both in AliceML, Mozart/Oz, and in the literature). From this perspective *all* variables are futures. For example, in the AliceML url you provide, they specifically qualify the different kinds of futures:
* concurrent futures --- something like Async
* lazy futures --- what Haskell has by default
* promised futures --- for tying the knot; akin to "static" in Java
Durr, I meant "final" for the non-static members in Java.
* immediate futures (not mentioned on the AliceML page) --- the standard all-at-once way of introducing, binding, and evaluating variables.
Of course, the concurrent/lazy/promised qualifiers can be combined since they define orthogonal axes of temporal distinction.
-- Live well, ~wren

On 08/06/12 10:37, Simon Marlow wrote:
I'd like to add a higher-level concurrency API to the base package.
How does this async package differ from monad-par, from a user's perspective? It seems that the latter is intended for pure computations and the implementation is more heavy weight. But it can be used for IO as well. The difference in API is essentially only that async lives in the IO monad, whereas monad-par has its own Par monad. Could and/or should one be implemented in terms of the other? Twan

On 15/06/2012 13:52, Twan van Laarhoven wrote:
On 08/06/12 10:37, Simon Marlow wrote:
I'd like to add a higher-level concurrency API to the base package.
How does this async package differ from monad-par, from a user's perspective? It seems that the latter is intended for pure computations and the implementation is more heavy weight. But it can be used for IO as well.
monad-par is for pure deterministic parallelism only, since it is based around runPar :: Par a -> a So I'm slightly confused by your comment that it can be used for IO as well - what do you mean exactly? I'd say monad-par is much more lightweight than async. Perhaps not in terms of the amount of code in the library, but the overhead of 'fork' in monad-par is much less than the overhead of 'async'. Incidentally, the IVar in monad-par is what I would call a "future" (in reference to the other suggestion that we use "Future" instead of "Async").
The difference in API is essentially only that async lives in the IO monad, whereas monad-par has its own Par monad.
Not being in IO is a pretty big difference :)
Could and/or should one be implemented in terms of the other?
We could implement monad-par in terms of Async, but I doubt it would make a lot of difference. The reverse is obviously not possible. Cheers, Simon

On 15/06/12 15:38, Simon Marlow wrote:
On 15/06/2012 13:52, Twan van Laarhoven wrote:
On 08/06/12 10:37, Simon Marlow wrote: monad-par is for pure deterministic parallelism only, since it is based around
runPar :: Par a -> a
So I'm slightly confused by your comment that it can be used for IO as well - what do you mean exactly?
I base this on the documentation of Control.Monad.Par.Unsafe: unsafeParIO :: IO a -> p a Lift an IO operation into the Par monad. These are unsafe (in the normal, Haskell sense) when used with a runPar of type `Par a -> a`. If used with a runParIO that stays in the IO monad, then they are simply dangerous. Twan

On 15/06/2012 15:42, Twan van Laarhoven wrote:
On 15/06/12 15:38, Simon Marlow wrote:
On 08/06/12 10:37, Simon Marlow wrote: monad-par is for pure deterministic parallelism only, since it is
On 15/06/2012 13:52, Twan van Laarhoven wrote: based around
runPar :: Par a -> a
So I'm slightly confused by your comment that it can be used for IO as well - what do you mean exactly?
I base this on the documentation of Control.Monad.Par.Unsafe:
unsafeParIO :: IO a -> p a Lift an IO operation into the Par monad. These are unsafe (in the normal, Haskell sense) when used with a runPar of type `Par a -> a`. If used with a runParIO that stays in the IO monad, then they are simply dangerous.
Ah, so runParIO is part of meta-par, not monad-par as such. There is no instance of ParUnsafe for the default monad-par scheduler. You have a point that with runParIO, meta-par is similar to Async. However, the goals are quite different: meta-par is aimed at parallel throughput rather than concurrency, so you don't necessarily get preemption and fairness like you do with forkIO and Async. If you do blocking IO inside unsafeParIO, it is likely that you'll block other threads, because meta-par is doing its own scheduling. So while you *can* do IO operations inside the Par monad, the reason is to allow nondeterministic parallel computations, rather than true concurrency. Cheers, Simon

Simon, Let me know if you want to proceed with this proposal after this initial batch of comments. If so I'll try to track the open issues more closely on the proposal's wiki page. -- Johan

On 15/06/2012 16:52, Johan Tibell wrote:
Let me know if you want to proceed with this proposal after this initial batch of comments. If so I'll try to track the open issues more closely on the proposal's wiki page.
I'm definitely keen to have the package in the platform. The main point against is that the package hasn't had a lot of testing in the wild; however I think the API is small and obvious enough that this isn't a problem. If you could help with tracking the open issues that would be great! Cheers, Simon

On Tue, Jul 3, 2012 at 7:08 AM, Simon Marlow
I'm definitely keen to have the package in the platform. The main point against is that the package hasn't had a lot of testing in the wild; however I think the API is small and obvious enough that this isn't a problem.
If you could help with tracking the open issues that would be great!
I'm a bit swamped this week but I could try to jot down some notes next week. In the meantime: If everyone could please consider the package for inclusion into HP (i.e. try to separate nice to haves from must haves) and list things that you think must be addressed before inclusion that'd be great. -- Johan
participants (18)
-
Chris Kuklewicz
-
Conrad Parker
-
Gábor Lehel
-
Heinrich Apfelmus
-
Heka Treep
-
Herbert Valerio Riedel
-
Ian Lynagh
-
Iavor Diatchki
-
Johan Tibell
-
Lauri Alanko
-
Michael Snoyman
-
Ross Paterson
-
Ryan Newton
-
Simon Marlow
-
Sjoerd Visscher
-
Thomas Schilling
-
Twan van Laarhoven
-
wren ng thornton