New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Task.parallel #223

Closed
TheSeamau5 opened this Issue Apr 22, 2015 · 11 comments

Comments

Projects
None yet
8 participants
@TheSeamau5
Contributor

TheSeamau5 commented Apr 22, 2015

This feature has been discussed previously in the mailing list, but the following thread brings a compelling case for this function: https://groups.google.com/forum/#!topic/elm-discuss/n-6Mh5KhF18

The idea behind a parallel function is to be able to simultaneously perform multiple requests (usually Http requests) and then collect a successful value only if all requests have succeeded or else collect an error value.

parallel : List (Task error value) -> Task error (List value)
-- alternatively, parallel : List (Task error value) -> Task (List error) (List value)

In essence, parallel would be analogous to sequence.

The use case that has come up from the mailing list is that you want to get a list of data (json objects) from the interwebs that you then wish to display. Except that you wish to display them progressively, as they come (as opposed to all at once or one by one).

parallel would allow to batch requests and thus, rather that display items one by one, you could display them 20 by 20, or 5 by 5, etc... These requests would be sent in parallel, thus theoretically making things faster (in theory you could get 5 responses as fast as you get 1 response).

@TheSeamau5

This comment has been minimized.

Show comment
Hide comment
@TheSeamau5

TheSeamau5 Apr 22, 2015

Contributor

Examples in the wild for copyi...cough...inspiration:

RQ

See example parallel function in Douglas Crockford's RQ library for async programming in JS.

Link to library: https://github.com/douglascrockford/RQ
Link to parallel function : https://github.com/douglascrockford/RQ/blob/master/rq.js#L279

Restling

From npm package : https://www.npmjs.com/package/restling

var rest  = require('restling');
var array = [{'url':'http://google.com'},
             {'url':'http://some/rest/api'}]

rest.settleAsync(array).then(function(result){
  // handle results here 
  // result is [responseFromGoogle, responseFromApi] 
},function(err){
  // handle error here 
});

rest.settleAsync takes an array of links returns a JS promise

jQuery

See the jQuery.when() function in jQuery.

The docs are already quite exhaustive but the language can be confusing. Here is a simple tutorial on that function that explains how it works simply: https://css-tricks.com/multiple-simultaneous-ajax-requests-one-callback-jquery/

Contributor

TheSeamau5 commented Apr 22, 2015

Examples in the wild for copyi...cough...inspiration:

RQ

See example parallel function in Douglas Crockford's RQ library for async programming in JS.

Link to library: https://github.com/douglascrockford/RQ
Link to parallel function : https://github.com/douglascrockford/RQ/blob/master/rq.js#L279

Restling

From npm package : https://www.npmjs.com/package/restling

var rest  = require('restling');
var array = [{'url':'http://google.com'},
             {'url':'http://some/rest/api'}]

rest.settleAsync(array).then(function(result){
  // handle results here 
  // result is [responseFromGoogle, responseFromApi] 
},function(err){
  // handle error here 
});

rest.settleAsync takes an array of links returns a JS promise

jQuery

See the jQuery.when() function in jQuery.

The docs are already quite exhaustive but the language can be confusing. Here is a simple tutorial on that function that explains how it works simply: https://css-tricks.com/multiple-simultaneous-ajax-requests-one-callback-jquery/

@TheSeamau5

This comment has been minimized.

Show comment
Hide comment
@TheSeamau5

TheSeamau5 Apr 22, 2015

Contributor

In working on the mailing list problem, I've stumbled, thanks to @johnpmayer's suggestion, on an implementation of parallel that is very useful and is entirely in Elm, using spawn. The difference is that it requires an Address to be passed to it so that it may do its thing.

parallel : Address a -> List (Task error a) -> Task error (List ThreadID)
parallel address tasks = 
  let
      sendToAddress task = spawn (task `andThen` send address) 
  in
      sequence (List.map sendToAddress tasks)
Contributor

TheSeamau5 commented Apr 22, 2015

In working on the mailing list problem, I've stumbled, thanks to @johnpmayer's suggestion, on an implementation of parallel that is very useful and is entirely in Elm, using spawn. The difference is that it requires an Address to be passed to it so that it may do its thing.

parallel : Address a -> List (Task error a) -> Task error (List ThreadID)
parallel address tasks = 
  let
      sendToAddress task = spawn (task `andThen` send address) 
  in
      sequence (List.map sendToAddress tasks)
@Raynos

This comment has been minimized.

Show comment
Hide comment
@Raynos

Raynos Apr 22, 2015

I've recently written a very efficient parallelCollect() function for doing N asynchronous things in parallel and collecting all the errors and results.

This implementation might help you ( https://gist.github.com/Raynos/ae3ac8aeb95c3b5ae956 ).

I paid special attention to allocating the minimum amount of closures necessary to be able to do this.

Raynos commented Apr 22, 2015

I've recently written a very efficient parallelCollect() function for doing N asynchronous things in parallel and collecting all the errors and results.

This implementation might help you ( https://gist.github.com/Raynos/ae3ac8aeb95c3b5ae956 ).

I paid special attention to allocating the minimum amount of closures necessary to be able to do this.

@johnpmayer

This comment has been minimized.

Show comment
Hide comment
@johnpmayer

johnpmayer Apr 22, 2015

Hmm. I'd rather be able to write this as a regular task without Mailboxes
or itself as native code. Sounds like we need an actually Promise
primitive, with succeed, fail, and wait. Parallel then becomes wait for
all.
On Apr 22, 2015 4:02 PM, "Raynos (Jake Verbaten)" notifications@github.com
wrote:

I've recently written a very efficient parallelCollect() function for
doing N asynchronous things in parallel and collecting all the errors and
results.

This implementation might help you (
https://gist.github.com/Raynos/ae3ac8aeb95c3b5ae956 ).

I paid special attention to allocating the minimum amount of closures
necessary to be able to do this.


Reply to this email directly or view it on GitHub
https://github.com/elm-lang/core/issues/223#issuecomment-95319826.

johnpmayer commented Apr 22, 2015

Hmm. I'd rather be able to write this as a regular task without Mailboxes
or itself as native code. Sounds like we need an actually Promise
primitive, with succeed, fail, and wait. Parallel then becomes wait for
all.
On Apr 22, 2015 4:02 PM, "Raynos (Jake Verbaten)" notifications@github.com
wrote:

I've recently written a very efficient parallelCollect() function for
doing N asynchronous things in parallel and collecting all the errors and
results.

This implementation might help you (
https://gist.github.com/Raynos/ae3ac8aeb95c3b5ae956 ).

I paid special attention to allocating the minimum amount of closures
necessary to be able to do this.


Reply to this email directly or view it on GitHub
https://github.com/elm-lang/core/issues/223#issuecomment-95319826.

@TheSeamau5

This comment has been minimized.

Show comment
Hide comment
@TheSeamau5

TheSeamau5 Apr 22, 2015

Contributor

Wow. The code is very Elm-like, it shouldn't be complicated to adapt to Elm.

By the way, I came up with a simpler implementation of parallel that doesn't require passing in the Address. Instead, you have to do the sending to the mailbox a priori.

parallel : List (Task error value) -> Task error (List ThreadID)
parallel = 
  sequence << List.map spawn
Contributor

TheSeamau5 commented Apr 22, 2015

Wow. The code is very Elm-like, it shouldn't be complicated to adapt to Elm.

By the way, I came up with a simpler implementation of parallel that doesn't require passing in the Address. Instead, you have to do the sending to the mailbox a priori.

parallel : List (Task error value) -> Task error (List ThreadID)
parallel = 
  sequence << List.map spawn
@etaque

This comment has been minimized.

Show comment
Hide comment
@etaque

etaque Jan 13, 2016

Just to bump the issue, parallel HTTP requests would have been very useful on the customer project I'm currently working now :)

etaque commented Jan 13, 2016

Just to bump the issue, parallel HTTP requests would have been very useful on the customer project I'm currently working now :)

@simonewebdesign

This comment has been minimized.

Show comment
Hide comment

simonewebdesign commented Jan 13, 2016

@etaque while we wait for a core implementation you can use this library: http://package.elm-lang.org/packages/TheSeamau5/elm-task-extra/2.0.0/Task-Extra#parallel

@etaque

This comment has been minimized.

Show comment
Hide comment
@etaque

etaque Jan 13, 2016

Yes, I've seen it but it's just a sequence (List.map spawn tasks). It's necessary to go through a mailbox if we need to get the results back, so it's a bit tedious (but doable).

etaque commented Jan 13, 2016

Yes, I've seen it but it's just a sequence (List.map spawn tasks). It's necessary to go through a mailbox if we need to get the results back, so it's a bit tedious (but doable).

@AlexGalays

This comment has been minimized.

Show comment
Hide comment
@AlexGalays

AlexGalays Jan 13, 2016

I had the need for the JS equivalent of this feature in every single apps I wrote in the past.
As a reminder, doing parallel http calls with JS is absolutely easy to do with Promise.all, hopefully Elm catch up soon :p

AlexGalays commented Jan 13, 2016

I had the need for the JS equivalent of this feature in every single apps I wrote in the past.
As a reminder, doing parallel http calls with JS is absolutely easy to do with Promise.all, hopefully Elm catch up soon :p

@evancz evancz referenced this issue Jun 25, 2016

Open

API Ideas #322

@evancz

This comment has been minimized.

Show comment
Hide comment
@evancz

evancz Jun 25, 2016

Member

This will be easy to implement in Elm once the Process library gets communication support as outlined here. Until then, I think it makes sense to track this in the meta issue about API ideas.

Member

evancz commented Jun 25, 2016

This will be easy to implement in Elm once the Process library gets communication support as outlined here. Until then, I think it makes sense to track this in the meta issue about API ideas.

@evancz evancz closed this Jun 25, 2016

@okkero

This comment has been minimized.

Show comment
Hide comment
@okkero

okkero Sep 6, 2017

Will this also (eventually) make it possible to have versions of the Task.mapN functions that run the tasks in parallel before collecting the results at the end?

okkero commented Sep 6, 2017

Will this also (eventually) make it possible to have versions of the Task.mapN functions that run the tasks in parallel before collecting the results at the end?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment